Merge m-c to b2g-inbound
authorWes Kocher <wkocher@mozilla.com>
Fri, 11 Oct 2013 18:59:44 -0700
changeset 164367 1e1848b4005075c97dae3e5c59b49e5f1361d629
parent 164366 895777ad56734bb6c1c972146df667a5a716e48b (current diff)
parent 164362 73f37c7a386094cfb79205529ef72ba1966509f4 (diff)
child 164368 97700fc8b02b7d2cd8342d33a3bd1b7b0629372a
push id3066
push userakeybl@mozilla.com
push dateMon, 09 Dec 2013 19:58:46 +0000
treeherdermozilla-beta@a31a0dce83aa [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone27.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge m-c to b2g-inbound
config/JarMaker.py
config/tests/unit-JarMaker.py
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1113,16 +1113,17 @@ pref("devtools.debugger.enabled", true);
 pref("devtools.debugger.chrome-enabled", true);
 pref("devtools.debugger.chrome-debugging-host", "localhost");
 pref("devtools.debugger.chrome-debugging-port", 6080);
 pref("devtools.debugger.remote-host", "localhost");
 pref("devtools.debugger.remote-timeout", 20000);
 pref("devtools.debugger.pause-on-exceptions", false);
 pref("devtools.debugger.ignore-caught-exceptions", true);
 pref("devtools.debugger.source-maps-enabled", true);
+pref("devtools.debugger.pretty-print-enabled", true);
 
 // The default Debugger UI settings
 pref("devtools.debugger.ui.panes-sources-width", 200);
 pref("devtools.debugger.ui.panes-instruments-width", 300);
 pref("devtools.debugger.ui.panes-visible-on-startup", false);
 pref("devtools.debugger.ui.variables-sorting-enabled", true);
 pref("devtools.debugger.ui.variables-only-enum-visible", false);
 pref("devtools.debugger.ui.variables-searchbox-visible", false);
--- a/browser/base/content/browser-gestureSupport.js
+++ b/browser/base/content/browser-gestureSupport.js
@@ -57,18 +57,19 @@ let gGestureSupport = {
     }
 
     // Create a preference object with some defaults
     let def = function(aThreshold, aLatched)
       ({ threshold: aThreshold, latched: !!aLatched });
 
     switch (aEvent.type) {
       case "MozSwipeGestureStart":
-        aEvent.preventDefault();
-        this._setupSwipeGesture(aEvent);
+        if (this._setupSwipeGesture(aEvent)) {
+          aEvent.preventDefault();
+        }
         break;
       case "MozSwipeGestureUpdate":
         aEvent.preventDefault();
         this._doUpdate(aEvent);
         break;
       case "MozSwipeGestureEnd":
         aEvent.preventDefault();
         this._doEnd(aEvent);
@@ -174,44 +175,66 @@ let gGestureSupport = {
               == "Browser:ForwardOrForwardDuplicate";
   },
 
   /**
    * Sets up the history swipe animations for a swipe gesture event, if enabled.
    *
    * @param aEvent
    *        The swipe gesture start event.
+   * @return true if swipe gestures could successfully be set up, false
+   *         othwerwise.
    */
   _setupSwipeGesture: function GS__setupSwipeGesture(aEvent) {
-    if (!this._swipeNavigatesHistory(aEvent))
-      return;
+    if (!this._swipeNavigatesHistory(aEvent)) {
+      return false;
+    }
+
+    let isVerticalSwipe = false;
+    if (gHistorySwipeAnimation.active) {
+      if (aEvent.direction == aEvent.DIRECTION_UP) {
+        if (content.pageYOffset > 0) {
+          return false;
+        }
+        isVerticalSwipe = true;
+      } else if (aEvent.direction == aEvent.DIRECTION_DOWN) {
+        if (content.pageYOffset < content.scrollMaxY) {
+          return false;
+        }
+        isVerticalSwipe = true;
+      }
+    }
 
     let canGoBack = gHistorySwipeAnimation.canGoBack();
     let canGoForward = gHistorySwipeAnimation.canGoForward();
     let isLTR = gHistorySwipeAnimation.isLTR;
 
-    if (canGoBack)
+    if (canGoBack) {
       aEvent.allowedDirections |= isLTR ? aEvent.DIRECTION_LEFT :
                                           aEvent.DIRECTION_RIGHT;
-    if (canGoForward)
+    }
+    if (canGoForward) {
       aEvent.allowedDirections |= isLTR ? aEvent.DIRECTION_RIGHT :
                                           aEvent.DIRECTION_LEFT;
+    }
 
-    gHistorySwipeAnimation.startAnimation();
+    gHistorySwipeAnimation.startAnimation(isVerticalSwipe);
 
     this._doUpdate = function GS__doUpdate(aEvent) {
       gHistorySwipeAnimation.updateAnimation(aEvent.delta);
     };
 
     this._doEnd = function GS__doEnd(aEvent) {
       gHistorySwipeAnimation.swipeEndEventReceived();
 
       this._doUpdate = function (aEvent) {};
       this._doEnd = function (aEvent) {};
     }
+
+    return true;
   },
 
   /**
    * Generator producing the powerset of the input array where the first result
    * is the complete set and the last result (before StopIteration) is empty.
    *
    * @param aArray
    *        Source array containing any number of elements
@@ -547,18 +570,20 @@ let gHistorySwipeAnimation = {
 
     this.active = false;
     this.isLTR = document.documentElement.mozMatchesSelector(
                                             ":-moz-locale-dir(ltr)");
     this._trackedSnapshots = [];
     this._startingIndex = -1;
     this._historyIndex = -1;
     this._boxWidth = -1;
+    this._boxHeight = -1;
     this._maxSnapshots = this._getMaxSnapshots();
     this._lastSwipeDir = "";
+    this._direction = "horizontal";
 
     // We only want to activate history swipe animations if we store snapshots.
     // If we don't store any, we handle horizontal swipes without animations.
     if (this._maxSnapshots > 0) {
       this.active = true;
       gBrowser.addEventListener("pagehide", this, false);
       gBrowser.addEventListener("pageshow", this, false);
       gBrowser.addEventListener("popstate", this, false);
@@ -579,24 +604,38 @@ let gHistorySwipeAnimation = {
 
     this.active = false;
     this.isLTR = false;
   },
 
   /**
    * Starts the swipe animation and handles fast swiping (i.e. a swipe animation
    * is already in progress when a new one is initiated).
+   *
+   * @param aIsVerticalSwipe
+   *        Whether we're dealing with a vertical swipe or not.
    */
-  startAnimation: function HSA_startAnimation() {
+  startAnimation: function HSA_startAnimation(aIsVerticalSwipe) {
+    this._direction = aIsVerticalSwipe ? "vertical" : "horizontal";
+
     if (this.isAnimationRunning()) {
-      gBrowser.stop();
-      this._lastSwipeDir = "RELOAD"; // just ensure that != ""
-      this._canGoBack = this.canGoBack();
-      this._canGoForward = this.canGoForward();
-      this._handleFastSwiping();
+      // If this is a horizontal scroll, or if this is a vertical scroll that
+      // was started while a horizontal scroll was still running, handle it as
+      // as a fast swipe. In the case of the latter scenario, this allows us to
+      // start the vertical animation without first loading the final page, or
+      // taking another snapshot. If vertical scrolls are initiated repeatedly
+      // without prior horizontal scroll we skip this and restart the animation
+      // from 0.
+      if (this._direction == "horizontal" || this._lastSwipeDir != "") {
+        gBrowser.stop();
+        this._lastSwipeDir = "RELOAD"; // just ensure that != ""
+        this._canGoBack = this.canGoBack();
+        this._canGoForward = this.canGoForward();
+        this._handleFastSwiping();
+      }
     }
     else {
       this._startingIndex = gBrowser.webNavigation.sessionHistory.index;
       this._historyIndex = this._startingIndex;
       this._canGoBack = this.canGoBack();
       this._canGoForward = this.canGoForward();
       if (this.active) {
         this._takeSnapshot();
@@ -618,58 +657,58 @@ let gHistorySwipeAnimation = {
   /**
    * Updates the animation between two pages in history.
    *
    * @param aVal
    *        A floating point value that represents the progress of the
    *        swipe gesture.
    */
   updateAnimation: function HSA_updateAnimation(aVal) {
-    if (!this.isAnimationRunning())
+    if (!this.isAnimationRunning()) {
       return;
+    }
 
-    // We use the following value to decrease the bounce effect when swiping
-    // back/forward past the browsing history. This value was determined
-    // experimentally.
+    // We use the following value to decrease the bounce effect when scrolling
+    // to the top or bottom of the page, or when swiping back/forward past the
+    // browsing history. This value was determined experimentally.
     let dampValue = 4;
-    if ((aVal >= 0 && this.isLTR) ||
-        (aVal <= 0 && !this.isLTR)) {
+    if (this._direction == "vertical") {
+      this._prevBox.collapsed = true;
+      this._nextBox.collapsed = true;
+      this._positionBox(this._curBox, -1 * aVal / dampValue);
+    } else if ((aVal >= 0 && this.isLTR) ||
+               (aVal <= 0 && !this.isLTR)) {
       let tempDampValue = 1;
-      if (this._canGoBack)
+      if (this._canGoBack) {
         this._prevBox.collapsed = false;
-      else {
+      } else {
         tempDampValue = dampValue;
         this._prevBox.collapsed = true;
       }
 
       // The current page is pushed to the right (LTR) or left (RTL),
       // the intention is to go back.
       // If there is a page to go back to, it should show in the background.
       this._positionBox(this._curBox, aVal / tempDampValue);
 
       // The forward page should be pushed offscreen all the way to the right.
       this._positionBox(this._nextBox, 1);
-    }
-    else {
-      if (aVal < -1)
-        aVal = -1; // Cap value to avoid sliding the page further than allowed.
-
+    } else {
       // The intention is to go forward. If there is a page to go forward to,
       // it should slide in from the right (LTR) or left (RTL).
       // Otherwise, the current page should slide to the left (LTR) or
       // right (RTL) and the backdrop should appear in the background.
       // For the backdrop to be visible in that case, the previous page needs
       // to be hidden (if it exists).
       if (this._canGoForward) {
         this._nextBox.collapsed = false;
         let offset = this.isLTR ? 1 : -1;
         this._positionBox(this._curBox, 0);
         this._positionBox(this._nextBox, offset + aVal);
-      }
-      else {
+      } else {
         this._prevBox.collapsed = true;
         this._positionBox(this._curBox, aVal / dampValue);
       }
     }
   },
 
   /**
    * Event handler for events relevant to the history swipe animation.
@@ -830,30 +869,33 @@ let gHistorySwipeAnimation = {
     this._curBox = this._createElement("historySwipeAnimationCurrentPage",
                                        "box");
     this._container.appendChild(this._curBox);
 
     this._nextBox = this._createElement("historySwipeAnimationNextPage",
                                         "box");
     this._container.appendChild(this._nextBox);
 
-    this._boxWidth = this._curBox.getBoundingClientRect().width; // cache width
+    // Cache width and height.
+    this._boxWidth = this._curBox.getBoundingClientRect().width;
+    this._boxHeight = this._curBox.getBoundingClientRect().height;
   },
 
   /**
    * Removes the boxes.
    */
   _removeBoxes: function HSA__removeBoxes() {
     this._curBox = null;
     this._prevBox = null;
     this._nextBox = null;
     if (this._container)
       this._container.parentNode.removeChild(this._container);
     this._container = null;
     this._boxWidth = -1;
+    this._boxHeight = -1;
   },
 
   /**
    * Creates an element with a given identifier and tag name.
    *
    * @param aID
    *        An identifier to create the element with.
    * @param aTagName
@@ -871,17 +913,24 @@ let gHistorySwipeAnimation = {
    * Moves a given box to a given X coordinate position.
    *
    * @param aBox
    *        The box element to position.
    * @param aPosition
    *        The position (in X coordinates) to move the box element to.
    */
   _positionBox: function HSA__positionBox(aBox, aPosition) {
-    aBox.style.transform = "translateX(" + this._boxWidth * aPosition + "px)";
+    let transform = "";
+
+    if (this._direction == "vertical")
+      transform = "translateY(" + this._boxHeight * aPosition + "px)";
+    else
+      transform = "translateX(" + this._boxWidth * aPosition + "px)";
+
+    aBox.style.transform = transform;
   },
 
   /**
    * Takes a snapshot of the page the browser is currently on.
    */
   _takeSnapshot: function HSA__takeSnapshot() {
     if ((this._maxSnapshots < 1) ||
         (gBrowser.webNavigation.sessionHistory.index < 0))
--- a/browser/devtools/debugger/debugger-controller.js
+++ b/browser/devtools/debugger/debugger-controller.js
@@ -1851,16 +1851,17 @@ let Prefs = new ViewHelpers.Prefs("devto
   instrumentsWidth: ["Int", "debugger.ui.panes-instruments-width"],
   panesVisibleOnStartup: ["Bool", "debugger.ui.panes-visible-on-startup"],
   variablesSortingEnabled: ["Bool", "debugger.ui.variables-sorting-enabled"],
   variablesOnlyEnumVisible: ["Bool", "debugger.ui.variables-only-enum-visible"],
   variablesSearchboxVisible: ["Bool", "debugger.ui.variables-searchbox-visible"],
   pauseOnExceptions: ["Bool", "debugger.pause-on-exceptions"],
   ignoreCaughtExceptions: ["Bool", "debugger.ignore-caught-exceptions"],
   sourceMapsEnabled: ["Bool", "debugger.source-maps-enabled"],
+  prettyPrintEnabled: ["Bool", "debugger.pretty-print-enabled"],
   editorTabSize: ["Int", "editor.tabsize"]
 });
 
 /**
  * Returns true if this is a chrome debugger instance.
  * @return boolean
  */
 XPCOMUtils.defineLazyGetter(window, "_isChromeDebugger", function() {
--- a/browser/devtools/debugger/debugger-panes.js
+++ b/browser/devtools/debugger/debugger-panes.js
@@ -49,16 +49,20 @@ SourcesView.prototype = Heritage.extend(
     this._popupset = document.getElementById("debuggerPopupset");
     this._cmPopup = document.getElementById("sourceEditorContextMenu");
     this._cbPanel = document.getElementById("conditional-breakpoint-panel");
     this._cbTextbox = document.getElementById("conditional-breakpoint-panel-textbox");
     this._editorDeck = document.getElementById("editor-deck");
     this._stopBlackBoxButton = document.getElementById("black-boxed-message-button");
     this._prettyPrintButton = document.getElementById("pretty-print");
 
+    if (Prefs.prettyPrintEnabled) {
+      this._prettyPrintButton.removeAttribute("hidden");
+    }
+
     window.on(EVENTS.EDITOR_LOADED, this._onEditorLoad, false);
     window.on(EVENTS.EDITOR_UNLOADED, this._onEditorUnload, false);
     this.widget.addEventListener("select", this._onSourceSelect, false);
     this.widget.addEventListener("click", this._onSourceClick, false);
     this.widget.addEventListener("check", this._onSourceCheck, false);
     this._stopBlackBoxButton.addEventListener("click", this._onStopBlackBoxing, false);
     this._prettyPrintButton.addEventListener("click", this.prettyPrint, false);
     this._cbPanel.addEventListener("popupshowing", this._onConditionalPopupShowing, false);
--- a/browser/devtools/debugger/debugger.xul
+++ b/browser/devtools/debugger/debugger.xul
@@ -323,17 +323,18 @@
           <vbox id="sources-pane" flex="1">
             <vbox id="sources" flex="1"/>
           </vbox>
           <toolbar id="sources-toolbar" class="devtools-toolbar">
             <toolbarbutton id="pretty-print"
                            label="{}"
                            tooltiptext="&debuggerUI.sources.prettyPrint;"
                            class="devtools-toolbarbutton devtools-monospace"
-                           command="prettyPrintCommand"/>
+                           command="prettyPrintCommand"
+                           hidden="true"/>
           </toolbar>
         </vbox>
         <splitter class="devtools-side-splitter"/>
         <deck id="editor-deck" flex="1" selectedIndex="0">
           <vbox id="editor"/>
           <vbox id="black-boxed-message" align="center">
             <label id="black-boxed-message-label">
               &debuggerUI.blackBoxMessage.label;
--- a/build/mach_bootstrap.py
+++ b/build/mach_bootstrap.py
@@ -103,16 +103,21 @@ CATEGORIES = {
         'short': 'Low-level Build System Interaction',
         'long': 'Interact with specific parts of the build system.',
         'priority': 20,
     },
     'misc': {
         'short': 'Potpourri',
         'long': 'Potent potables and assorted snacks.',
         'priority': 10,
+    },
+    'disabled': {
+        'short': 'Disabled',
+        'long': 'These commands are unavailable for your current context, run "mach <command>" to see why.',
+        'priority': 0,
     }
 }
 
 
 def bootstrap(topsrcdir, mozilla_dir=None):
     if mozilla_dir is None:
         mozilla_dir = topsrcdir
 
@@ -162,18 +167,19 @@ def bootstrap(topsrcdir, mozilla_dir=Non
     try:
         import mach.main
     except ImportError:
         sys.path[0:0] = [os.path.join(mozilla_dir, path) for path in SEARCH_PATHS]
         import mach.main
 
     def populate_context(context):
         context.state_dir = state_dir
+        context.topdir = topsrcdir
 
-    mach = mach.main.Mach(topsrcdir)
+    mach = mach.main.Mach(os.getcwd())
     mach.populate_context_handler = populate_context
 
     for category, meta in CATEGORIES.items():
         mach.define_category(category, meta['short'], meta['long'],
             meta['priority'])
 
     for path in MACH_MODULES:
         mach.load_commands_from_file(os.path.join(mozilla_dir, path))
--- a/config/config.mk
+++ b/config/config.mk
@@ -347,17 +347,16 @@ DEFINES += \
 	  -DIMPL_LIBXUL \
 		$(NULL)
 
 ifndef JS_SHARED_LIBRARY
 DEFINES += -DSTATIC_EXPORTABLE_JS_API
 endif
 endif
 
-# Flags passed to JarMaker.py
 MAKE_JARS_FLAGS = \
 	-t $(topsrcdir) \
 	-f $(MOZ_CHROME_FILE_FORMAT) \
 	$(NULL)
 
 ifdef USE_EXTENSION_MANIFEST
 MAKE_JARS_FLAGS += -e
 endif
--- a/config/rules.mk
+++ b/config/rules.mk
@@ -1446,20 +1446,20 @@ endif
 ifneq (,$(DIST_SUBDIR))
 ifndef XPI_ROOT_APPID
 $(error XPI_ROOT_APPID is not defined - langpacks will break.)
 endif
 endif
 endif
 
 libs realchrome:: $(CHROME_DEPS) $(FINAL_TARGET)/chrome
-	$(PYTHON) $(MOZILLA_DIR)/config/JarMaker.py \
+	$(call py_action,jar_maker,\
 	  $(QUIET) -j $(FINAL_TARGET)/chrome \
 	  $(MAKE_JARS_FLAGS) $(XULPPFLAGS) $(DEFINES) $(ACDEFINES) \
-	  $(JAR_MANIFEST)
+	  $(JAR_MANIFEST))
 
 endif
 endif
 
 ifneq ($(DIST_FILES),)
 DIST_FILES_PATH := $(FINAL_TARGET)
 DIST_FILES_FLAGS := $(XULAPP_DEFINES)
 PP_TARGETS += DIST_FILES
--- a/content/base/public/nsINode.h
+++ b/content/base/public/nsINode.h
@@ -15,16 +15,17 @@
 #include "nsNodeInfoManager.h"      // for use in NodePrincipal()
 #include "nsPropertyTable.h"        // for typedefs
 #include "nsTObserverArray.h"       // for member
 #include "nsWindowMemoryReporter.h" // for NS_DECL_SIZEOF_EXCLUDING_THIS
 #include "mozilla/ErrorResult.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/dom/EventTarget.h" // for base class
 #include "js/TypeDecls.h"     // for Handle, Value, JSObject, JSContext
+#include "mozilla/dom/DOMString.h"
 
 // Including 'windows.h' will #define GetClassInfo to something else.
 #ifdef XP_WIN
 #ifdef GetClassInfo
 #undef GetClassInfo
 #endif
 #endif
 
@@ -1478,19 +1479,21 @@ public:
   void GetBoundMutationObservers(nsTArray<nsRefPtr<nsDOMMutationObserver> >& aResult);
 
   /**
    * Returns the length of this node, as specified at
    * <http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node-length>
    */
   uint32_t Length() const;
 
-  void GetNodeName(nsAString& aNodeName) const
+  void GetNodeName(mozilla::dom::DOMString& aNodeName)
   {
-    aNodeName = NodeName();
+    const nsString& nodeName = NodeName();
+    aNodeName.SetStringBuffer(nsStringBuffer::FromString(nodeName),
+                              nodeName.Length());
   }
   void GetBaseURI(nsAString& aBaseURI) const;
   bool HasChildNodes() const
   {
     return HasChildren();
   }
   uint16_t CompareDocumentPosition(nsINode& aOther) const;
   void GetNodeValue(nsAString& aNodeValue)
@@ -1531,19 +1534,25 @@ public:
     mNodeInfo->GetNamespaceURI(aNamespaceURI);
   }
 #ifdef MOZILLA_INTERNAL_API
   void GetPrefix(nsAString& aPrefix)
   {
     mNodeInfo->GetPrefix(aPrefix);
   }
 #endif
-  void GetLocalName(nsAString& aLocalName)
+  void GetLocalName(mozilla::dom::DOMString& aLocalName)
   {
-    aLocalName = mNodeInfo->LocalName();
+    const nsString& localName = LocalName();
+    if (localName.IsVoid()) {
+      aLocalName.SetNull();
+    } else {
+      aLocalName.SetStringBuffer(nsStringBuffer::FromString(localName),
+                                 localName.Length());
+    }
   }
   // HasAttributes is defined inline in Element.h.
   bool HasAttributes() const;
   nsDOMAttributeMap* GetAttributes();
   JS::Value SetUserData(JSContext* aCx, const nsAString& aKey,
                         JS::Handle<JS::Value> aData,
                         nsIDOMUserDataHandler* aHandler,
                         mozilla::ErrorResult& aError);
@@ -1751,17 +1760,17 @@ inline nsISupports*
 ToCanonicalSupports(nsINode* aPointer)
 {
   return aPointer;
 }
 
 #define NS_FORWARD_NSIDOMNODE_TO_NSINODE_HELPER(...) \
   NS_IMETHOD GetNodeName(nsAString& aNodeName) __VA_ARGS__ \
   { \
-    nsINode::GetNodeName(aNodeName); \
+    aNodeName = nsINode::NodeName(); \
     return NS_OK; \
   } \
   NS_IMETHOD GetNodeValue(nsAString& aNodeValue) __VA_ARGS__ \
   { \
     nsINode::GetNodeValue(aNodeValue); \
     return NS_OK; \
   } \
   NS_IMETHOD SetNodeValue(const nsAString& aNodeValue) __VA_ARGS__ \
@@ -1853,17 +1862,17 @@ ToCanonicalSupports(nsINode* aPointer)
   } \
   NS_IMETHOD GetPrefix(nsAString& aPrefix) __VA_ARGS__ \
   { \
     nsINode::GetPrefix(aPrefix); \
     return NS_OK; \
   } \
   NS_IMETHOD GetLocalName(nsAString& aLocalName) __VA_ARGS__ \
   { \
-    nsINode::GetLocalName(aLocalName); \
+    aLocalName = nsINode::LocalName(); \
     return NS_OK; \
   } \
   using nsINode::HasAttributes; \
   NS_IMETHOD HasAttributes(bool* aResult) __VA_ARGS__ \
   { \
     *aResult = nsINode::HasAttributes(); \
     return NS_OK; \
   } \
--- a/content/base/src/nsXMLHttpRequest.h
+++ b/content/base/src/nsXMLHttpRequest.h
@@ -277,16 +277,23 @@ public:
 
   // event handler
   IMPL_EVENT_HANDLER(readystatechange)
 
   // states
   uint16_t ReadyState();
 
   // request
+  void Open(const nsACString& aMethod, const nsAString& aUrl, ErrorResult& aRv)
+  {
+    Open(aMethod, aUrl, true,
+         mozilla::dom::Optional<nsAString>(),
+         mozilla::dom::Optional<nsAString>(),
+         aRv);
+  }
   void Open(const nsACString& aMethod, const nsAString& aUrl, bool aAsync,
             const mozilla::dom::Optional<nsAString>& aUser,
             const mozilla::dom::Optional<nsAString>& aPassword,
             ErrorResult& aRv)
   {
     aRv = Open(aMethod, NS_ConvertUTF16toUTF8(aUrl),
                aAsync, aUser, aPassword);
   }
--- a/content/base/test/test_createHTMLDocument.html
+++ b/content/base/test/test_createHTMLDocument.html
@@ -22,29 +22,33 @@ function checkDoc(title, expectedtitle, 
   // Opera doesn't have a doctype: DSK-311092
   ok(doc.doctype, "Need a doctype");
   is(doc.doctype.name, "html");
   is(doc.doctype.publicId, "");
   is(doc.doctype.systemId, "");
   is(doc.doctype.internalSubset, null, "internalSubset should be null!");
   isElement(doc.documentElement, "html");
   isElement(doc.documentElement.firstChild, "head");
-  is(doc.documentElement.firstChild.childNodes.length, 1);
-  isElement(doc.documentElement.firstChild.firstChild, "title");
-  // Doesn't always work out in WebKit.
-  ok(doc.documentElement.firstChild.firstChild.firstChild, "Need a text node.");
-  is(doc.documentElement.firstChild.firstChild.firstChild.data, expectedtitle);
+  if (title !== undefined) {
+    is(doc.documentElement.firstChild.childNodes.length, 1);
+    isElement(doc.documentElement.firstChild.firstChild, "title");
+    // Doesn't always work out in WebKit.
+    ok(doc.documentElement.firstChild.firstChild.firstChild, "Need a text node.");
+    is(doc.documentElement.firstChild.firstChild.firstChild.data, expectedtitle);
+  } else {
+    is(doc.documentElement.firstChild.childNodes.length, 0);
+  }
   isElement(doc.documentElement.lastChild, "body");
   is(doc.documentElement.lastChild.childNodes.length, 0);
   ((!title || title.indexOf("\f") === -1) ? is : todo_is)
     (doc.title, normalizedtitle);
   doc.body.innerHTML = "foo";
   is(doc.body.innerHTML, "foo", "innerHTML should work in HTML data documents!");
 }
 checkDoc("", "", "");
 checkDoc(null, "null", "null");
-checkDoc(undefined, "undefined", "undefined");
+checkDoc(undefined, "", "");
 checkDoc("foo  bar baz", "foo  bar baz", "foo bar baz");
 checkDoc("foo\t\tbar baz", "foo\t\tbar baz", "foo bar baz");
 checkDoc("foo\n\nbar baz", "foo\n\nbar baz", "foo bar baz");
 checkDoc("foo\f\fbar baz", "foo\f\fbar baz", "foo bar baz");
 checkDoc("foo\r\rbar baz", "foo\r\rbar baz", "foo bar baz");
 </script>
--- a/content/events/src/nsEventStateManager.cpp
+++ b/content/events/src/nsEventStateManager.cpp
@@ -264,29 +264,81 @@ struct DeltaValues
     deltaX(aEvent->deltaX), deltaY(aEvent->deltaY)
   {
   }
 
   double deltaX;
   double deltaY;
 };
 
+/******************************************************************/
+/* nsScrollbarsForWheel                                           */
+/******************************************************************/
+
+class nsScrollbarsForWheel {
+public:
+  static void PrepareToScrollText(nsEventStateManager* aESM,
+                                  nsIFrame* aTargetFrame,
+                                  WheelEvent* aEvent);
+  static void SetActiveScrollTarget(nsIScrollableFrame* aScrollTarget);
+  // Hide all scrollbars (both mActiveOwner's and mActivatedScrollTargets')
+  static void MayInactivate();
+  static void Inactivate();
+  static bool IsActive();
+  static void OwnWheelTransaction(bool aOwn);
+
+protected:
+  static const size_t         kNumberOfTargets = 4;
+  static const DeltaValues    directions[kNumberOfTargets];
+  static nsWeakFrame          sActiveOwner;
+  static nsWeakFrame          sActivatedScrollTargets[kNumberOfTargets];
+  static bool                 sHadWheelStart;
+  static bool                 sOwnWheelTransaction;
+
+
+  /**
+   * These two methods are called upon NS_WHEEL_START/NS_WHEEL_STOP events
+   * to show/hide the right scrollbars.
+   */
+  static void TemporarilyActivateAllPossibleScrollTargets(
+                                  nsEventStateManager* aESM,
+                                  nsIFrame* aTargetFrame,
+                                  WheelEvent* aEvent);
+  static void DeactivateAllTemporarilyActivatedScrollTargets();
+};
+
+const DeltaValues nsScrollbarsForWheel::directions[kNumberOfTargets] = {
+  DeltaValues(-1, 0), DeltaValues(+1, 0), DeltaValues(0, -1), DeltaValues(0, +1)
+};
+nsWeakFrame nsScrollbarsForWheel::sActiveOwner = nullptr;
+nsWeakFrame nsScrollbarsForWheel::sActivatedScrollTargets[kNumberOfTargets] = {
+  nullptr, nullptr, nullptr, nullptr
+};
+bool nsScrollbarsForWheel::sHadWheelStart = false;
+bool nsScrollbarsForWheel::sOwnWheelTransaction = false;
+
+/******************************************************************/
+/* nsMouseWheelTransaction                                        */
+/******************************************************************/
+
 class nsMouseWheelTransaction {
 public:
   static nsIFrame* GetTargetFrame() { return sTargetFrame; }
   static void BeginTransaction(nsIFrame* aTargetFrame,
                                WheelEvent* aEvent);
   // Be careful, UpdateTransaction may fire a DOM event, therefore, the target
   // frame might be destroyed in the event handler.
   static bool UpdateTransaction(WheelEvent* aEvent);
+  static void MayEndTransaction();
   static void EndTransaction();
   static void OnEvent(WidgetEvent* aEvent);
   static void Shutdown();
   static uint32_t GetTimeoutTime();
 
+  static void OwnScrollbars(bool aOwn);
 
   static DeltaValues AccelerateWheelDelta(WheelEvent* aEvent,
                                           bool aAllowScrollSpeedOverride);
 
   enum {
     kScrollSeriesTimeout = 80
   };
 protected:
@@ -294,66 +346,78 @@ protected:
   static void OnFailToScrollTarget();
   static void OnTimeout(nsITimer *aTimer, void *aClosure);
   static void SetTimeout();
   static uint32_t GetIgnoreMoveDelayTime();
   static int32_t GetAccelerationStart();
   static int32_t GetAccelerationFactor();
   static DeltaValues OverrideSystemScrollSpeed(WheelEvent* aEvent);
   static double ComputeAcceleratedWheelDelta(double aDelta, int32_t aFactor);
+  static bool OutOfTime(uint32_t aBaseTime, uint32_t aThreshold);
 
   static nsWeakFrame sTargetFrame;
   static uint32_t    sTime;        // in milliseconds
   static uint32_t    sMouseMoved;  // in milliseconds
   static nsITimer*   sTimer;
   static int32_t     sScrollSeriesCounter;
+  static bool        sOwnScrollbars;
 };
 
 nsWeakFrame nsMouseWheelTransaction::sTargetFrame(nullptr);
 uint32_t    nsMouseWheelTransaction::sTime        = 0;
 uint32_t    nsMouseWheelTransaction::sMouseMoved  = 0;
 nsITimer*   nsMouseWheelTransaction::sTimer       = nullptr;
 int32_t     nsMouseWheelTransaction::sScrollSeriesCounter = 0;
-
-static bool
-OutOfTime(uint32_t aBaseTime, uint32_t aThreshold)
-{
-  uint32_t now = PR_IntervalToMilliseconds(PR_IntervalNow());
-  return (now - aBaseTime > aThreshold);
-}
+bool        nsMouseWheelTransaction::sOwnScrollbars = false;
 
 static bool
 CanScrollInRange(nscoord aMin, nscoord aValue, nscoord aMax, double aDirection)
 {
   return aDirection > 0.0 ? aValue < static_cast<double>(aMax) :
                             static_cast<double>(aMin) < aValue;
 }
 
 static bool
-CanScrollOn(nsIScrollableFrame* aScrollFrame, double aDeltaX, double aDeltaY)
+CanScrollOn(nsIScrollableFrame* aScrollFrame, double aDirectionX, double aDirectionY)
 {
   MOZ_ASSERT(aScrollFrame);
-  NS_ASSERTION(aDeltaX || aDeltaY,
+  NS_ASSERTION(aDirectionX || aDirectionY,
                "One of the delta values must be non-zero at least");
 
   nsPoint scrollPt = aScrollFrame->GetScrollPosition();
   nsRect scrollRange = aScrollFrame->GetScrollRange();
   uint32_t directions = aScrollFrame->GetPerceivedScrollingDirections();
 
-  return (aDeltaX && (directions & nsIScrollableFrame::HORIZONTAL) &&
-          CanScrollInRange(scrollRange.x, scrollPt.x, scrollRange.XMost(), aDeltaX)) ||
-         (aDeltaY && (directions & nsIScrollableFrame::VERTICAL) &&
-          CanScrollInRange(scrollRange.y, scrollPt.y, scrollRange.YMost(), aDeltaY));
+  return (aDirectionX && (directions & nsIScrollableFrame::HORIZONTAL) &&
+          CanScrollInRange(scrollRange.x, scrollPt.x, scrollRange.XMost(), aDirectionX)) ||
+         (aDirectionY && (directions & nsIScrollableFrame::VERTICAL) &&
+          CanScrollInRange(scrollRange.y, scrollPt.y, scrollRange.YMost(), aDirectionY));
+}
+
+bool
+nsMouseWheelTransaction::OutOfTime(uint32_t aBaseTime, uint32_t aThreshold)
+{
+  uint32_t now = PR_IntervalToMilliseconds(PR_IntervalNow());
+  return (now - aBaseTime > aThreshold);
+}
+
+void
+nsMouseWheelTransaction::OwnScrollbars(bool aOwn)
+{
+  sOwnScrollbars = aOwn;
 }
 
 void
 nsMouseWheelTransaction::BeginTransaction(nsIFrame* aTargetFrame,
                                           WheelEvent* aEvent)
 {
   NS_ASSERTION(!sTargetFrame, "previous transaction is not finished!");
+  MOZ_ASSERT(aEvent->message == NS_WHEEL_WHEEL,
+             "Transaction must be started with a wheel event");
+  nsScrollbarsForWheel::OwnWheelTransaction(false);
   sTargetFrame = aTargetFrame;
   sScrollSeriesCounter = 0;
   if (!UpdateTransaction(aEvent)) {
     NS_ERROR("BeginTransaction is called even cannot scroll the frame");
     EndTransaction();
   }
 }
 
@@ -381,22 +445,37 @@ nsMouseWheelTransaction::UpdateTransacti
   // 2. If the computer runs slowly by other processes eating the CPU resource,
   //    the event creation time doesn't keep real time.
   sTime = PR_IntervalToMilliseconds(PR_IntervalNow());
   sMouseMoved = 0;
   return true;
 }
 
 void
+nsMouseWheelTransaction::MayEndTransaction()
+{
+  if (!sOwnScrollbars && nsScrollbarsForWheel::IsActive()) {
+    nsScrollbarsForWheel::OwnWheelTransaction(true);
+  } else {
+    EndTransaction();
+  }
+}
+
+void
 nsMouseWheelTransaction::EndTransaction()
 {
   if (sTimer)
     sTimer->Cancel();
   sTargetFrame = nullptr;
   sScrollSeriesCounter = 0;
+  if (sOwnScrollbars) {
+    sOwnScrollbars = false;
+    nsScrollbarsForWheel::OwnWheelTransaction(false);
+    nsScrollbarsForWheel::Inactivate();
+  }
 }
 
 void
 nsMouseWheelTransaction::OnEvent(WidgetEvent* aEvent)
 {
   if (!sTargetFrame)
     return;
 
@@ -410,28 +489,28 @@ nsMouseWheelTransaction::OnEvent(WidgetE
   }
 
   switch (aEvent->message) {
     case NS_WHEEL_WHEEL:
       if (sMouseMoved != 0 &&
           OutOfTime(sMouseMoved, GetIgnoreMoveDelayTime())) {
         // Terminate the current mousewheel transaction if the mouse moved more
         // than ignoremovedelay milliseconds ago
-        EndTransaction();
+        MayEndTransaction();
       }
       return;
     case NS_MOUSE_MOVE:
     case NS_DRAGDROP_OVER:
       if (IsMouseEventReal(aEvent)) {
         // If the cursor is moving to be outside the frame,
         // terminate the scrollwheel transaction.
         nsIntPoint pt = GetScreenPoint(static_cast<WidgetGUIEvent*>(aEvent));
         nsIntRect r = sTargetFrame->GetScreenRectExternal();
         if (!r.Contains(pt)) {
-          EndTransaction();
+          MayEndTransaction();
           return;
         }
 
         // If the cursor is moving inside the frame, and it is less than
         // ignoremovedelay milliseconds since the last scroll operation, ignore
         // the mouse move; otherwise, record the current mouse move time to be
         // checked later
         if (OutOfTime(sTime, GetIgnoreMoveDelayTime())) {
@@ -470,33 +549,34 @@ nsMouseWheelTransaction::OnFailToScrollT
     nsContentUtils::DispatchTrustedEvent(
                       sTargetFrame->GetContent()->OwnerDoc(),
                       sTargetFrame->GetContent(),
                       NS_LITERAL_STRING("MozMouseScrollFailed"),
                       true, true);
   }
   // The target frame might be destroyed in the event handler, at that time,
   // we need to finish the current transaction
-  if (!sTargetFrame)
+  if (!sTargetFrame) {
     EndTransaction();
+  }
 }
 
 void
 nsMouseWheelTransaction::OnTimeout(nsITimer* aTimer, void* aClosure)
 {
   if (!sTargetFrame) {
     // The transaction target was destroyed already
     EndTransaction();
     return;
   }
   // Store the sTargetFrame, the variable becomes null in EndTransaction.
   nsIFrame* frame = sTargetFrame;
   // We need to finish current transaction before DOM event firing. Because
   // the next DOM event might create strange situation for us.
-  EndTransaction();
+  MayEndTransaction();
 
   if (Preferences::GetBool("test.mousescroll", false)) {
     // This event is used for automated tests, see bug 442774.
     nsContentUtils::DispatchTrustedEvent(
                       frame->GetContent()->OwnerDoc(),
                       frame->GetContent(),
                       NS_LITERAL_STRING("MozMouseScrollTransactionTimeout"),
                       true, true);
@@ -621,16 +701,137 @@ nsMouseWheelTransaction::OverrideSystemS
   nsresult rv =
     widget->OverrideSystemMouseScrollSpeed(aEvent->deltaX, aEvent->deltaY,
                                            overriddenDeltaValues.deltaX,
                                            overriddenDeltaValues.deltaY);
   return NS_FAILED(rv) ? DeltaValues(aEvent) : overriddenDeltaValues;
 }
 
 /******************************************************************/
+/* nsScrollbarsForWheel                                           */
+/******************************************************************/
+
+void
+nsScrollbarsForWheel::PrepareToScrollText(
+                                  nsEventStateManager* aESM,
+                                  nsIFrame* aTargetFrame,
+                                  WheelEvent* aEvent)
+{
+  if (aEvent->message == NS_WHEEL_START) {
+    nsMouseWheelTransaction::OwnScrollbars(false);
+    if (!IsActive()) {
+      TemporarilyActivateAllPossibleScrollTargets(aESM, aTargetFrame, aEvent);
+      sHadWheelStart = true;
+    }
+  } else {
+    DeactivateAllTemporarilyActivatedScrollTargets();
+  }
+}
+
+void
+nsScrollbarsForWheel::SetActiveScrollTarget(nsIScrollableFrame* aScrollTarget)
+{
+  if (!sHadWheelStart) {
+    return;
+  }
+  nsIScrollbarOwner* scrollbarOwner = do_QueryFrame(aScrollTarget);
+  if (!scrollbarOwner) {
+    return;
+  }
+  sHadWheelStart = false;
+  sActiveOwner = do_QueryFrame(aScrollTarget);
+  scrollbarOwner->ScrollbarActivityStarted();
+}
+
+void
+nsScrollbarsForWheel::MayInactivate()
+{
+  if (!sOwnWheelTransaction && nsMouseWheelTransaction::GetTargetFrame()) {
+    nsMouseWheelTransaction::OwnScrollbars(true);
+  } else {
+    Inactivate();
+  }
+}
+
+void
+nsScrollbarsForWheel::Inactivate()
+{
+  nsIScrollbarOwner* scrollbarOwner = do_QueryFrame(sActiveOwner);
+  if (scrollbarOwner) {
+    scrollbarOwner->ScrollbarActivityStopped();
+  }
+  sActiveOwner = nullptr;
+  DeactivateAllTemporarilyActivatedScrollTargets();
+  if (sOwnWheelTransaction) {
+    sOwnWheelTransaction = false;
+    nsMouseWheelTransaction::OwnScrollbars(false);
+    nsMouseWheelTransaction::EndTransaction();
+  }
+}
+
+bool
+nsScrollbarsForWheel::IsActive()
+{
+  if (sActiveOwner) {
+    return true;
+  }
+  for (size_t i = 0; i < kNumberOfTargets; ++i) {
+    if (sActivatedScrollTargets[i]) {
+      return true;
+    }
+  }
+  return false;
+}
+
+void
+nsScrollbarsForWheel::OwnWheelTransaction(bool aOwn)
+{
+  sOwnWheelTransaction = aOwn;
+}
+
+void
+nsScrollbarsForWheel::TemporarilyActivateAllPossibleScrollTargets(
+                                               nsEventStateManager* aESM,
+                                               nsIFrame* aTargetFrame,
+                                               WheelEvent* aEvent)
+{
+  for (size_t i = 0; i < kNumberOfTargets; i++) {
+    const DeltaValues *dir = &directions[i];
+    nsWeakFrame* scrollTarget = &sActivatedScrollTargets[i];
+    MOZ_ASSERT(!*scrollTarget, "scroll target still temporarily activated!");
+    nsIScrollableFrame* target =
+      aESM->ComputeScrollTarget(aTargetFrame, dir->deltaX, dir->deltaY, aEvent, 
+                                nsEventStateManager::COMPUTE_DEFAULT_ACTION_TARGET);
+    if (target) {
+      nsIScrollbarOwner* scrollbarOwner = do_QueryFrame(target);
+      if (scrollbarOwner) {
+        nsIFrame* targetFrame = do_QueryFrame(target);
+        *scrollTarget = targetFrame;
+        scrollbarOwner->ScrollbarActivityStarted();
+      }
+    }
+  }
+}
+
+void
+nsScrollbarsForWheel::DeactivateAllTemporarilyActivatedScrollTargets()
+{
+  for (size_t i = 0; i < kNumberOfTargets; i++) {
+    nsWeakFrame* scrollTarget = &sActivatedScrollTargets[i];
+    if (*scrollTarget) {
+      nsIScrollbarOwner* scrollbarOwner = do_QueryFrame(*scrollTarget);
+      if (scrollbarOwner) {
+        scrollbarOwner->ScrollbarActivityStopped();
+      }
+      *scrollTarget = nullptr;
+    }
+  }
+}
+
+/******************************************************************/
 /* nsEventStateManager                                            */
 /******************************************************************/
 
 nsEventStateManager::nsEventStateManager()
   : mLockCursor(0),
     mPreLockPoint(0,0),
     mCurrentTarget(nullptr),
     mLastMouseOverFrame(nullptr),
@@ -972,23 +1173,30 @@ nsEventStateManager::PreHandleEvent(nsPr
   case NS_KEY_UP:
     {
       nsIContent* content = GetFocusedContent();
       if (content)
         mCurrentTargetContent = content;
     }
     break;
   case NS_WHEEL_WHEEL:
+  case NS_WHEEL_START:
+  case NS_WHEEL_STOP:
     {
       NS_ASSERTION(aEvent->mFlags.mIsTrusted,
                    "Untrusted wheel event shouldn't be here");
 
       nsIContent* content = GetFocusedContent();
-      if (content)
+      if (content) {
         mCurrentTargetContent = content;
+      }
+
+      if (aEvent->message != NS_WHEEL_WHEEL) {
+        break;
+      }
 
       WheelEvent* wheelEvent = static_cast<WheelEvent*>(aEvent);
       WheelPrefs::GetInstance()->ApplyUserPrefsToDelta(wheelEvent);
 
       // If we won't dispatch a DOM event for this event, nothing to do anymore.
       if (!wheelEvent->IsAllowedToDispatchDOMEvent()) {
         break;
       }
@@ -2541,16 +2749,30 @@ nsEventStateManager::SendPixelScrollEven
                               &event, nullptr, aStatus);
 }
 
 nsIScrollableFrame*
 nsEventStateManager::ComputeScrollTarget(nsIFrame* aTargetFrame,
                                          WheelEvent* aEvent,
                                          ComputeScrollTargetOptions aOptions)
 {
+  return ComputeScrollTarget(aTargetFrame, aEvent->deltaX, aEvent->deltaY,
+                             aEvent, aOptions);
+}
+
+// Overload ComputeScrollTarget method to allow passing "test" dx and dy when looking
+// for which scrollbarowners to activate when two finger down on trackpad
+// and before any actual motion
+nsIScrollableFrame*
+nsEventStateManager::ComputeScrollTarget(nsIFrame* aTargetFrame,
+                                         double aDirectionX,
+                                         double aDirectionY,
+                                         WheelEvent* aEvent,
+                                         ComputeScrollTargetOptions aOptions)
+{
   if (aOptions & PREFER_MOUSE_WHEEL_TRANSACTION) {
     // If the user recently scrolled with the mousewheel, then they probably
     // want to scroll the same view as before instead of the view under the
     // cursor.  nsMouseWheelTransaction tracks the frame currently being
     // scrolled with the mousewheel. We consider the transaction ended when the
     // mouse moves more than "mousewheel.transaction.ignoremovedelay"
     // milliseconds after the last scroll operation, or any time the mouse moves
     // out of the frame, or when more than "mousewheel.transaction.timeout"
@@ -2564,24 +2786,24 @@ nsEventStateManager::ComputeScrollTarget
         return frameToScroll;
       }
     }
   }
 
   // If the event doesn't cause scroll actually, we cannot find scroll target
   // because we check if the event can cause scroll actually on each found
   // scrollable frame.
-  if (!aEvent->deltaX && !aEvent->deltaY) {
+  if (!aDirectionX && !aDirectionY) {
     return nullptr;
   }
 
   bool checkIfScrollableX =
-    aEvent->deltaX && (aOptions & PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_X_AXIS);
+    aDirectionX && (aOptions & PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_X_AXIS);
   bool checkIfScrollableY =
-    aEvent->deltaY && (aOptions & PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_Y_AXIS);
+    aDirectionY && (aOptions & PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_Y_AXIS);
 
   nsIScrollableFrame* frameToScroll = nullptr;
   nsIFrame* scrollFrame =
     !(aOptions & START_FROM_PARENT) ? aTargetFrame :
                                       GetParentFrameToScroll(aTargetFrame);
   for (; scrollFrame; scrollFrame = GetParentFrameToScroll(scrollFrame)) {
     // Check whether the frame wants to provide us with a scrollable view.
     frameToScroll = scrollFrame->GetScrollTargetFrame();
@@ -2599,18 +2821,17 @@ nsEventStateManager::ComputeScrollTarget
     if ((hiddenForV && hiddenForH) ||
         (checkIfScrollableY && !checkIfScrollableX && hiddenForV) ||
         (checkIfScrollableX && !checkIfScrollableY && hiddenForH)) {
       continue;
     }
 
     // For default action, we should climb up the tree if cannot scroll it
     // by the event actually.
-    bool canScroll = CanScrollOn(frameToScroll,
-                                 aEvent->deltaX, aEvent->deltaY);
+    bool canScroll = CanScrollOn(frameToScroll, aDirectionX, aDirectionY);
     // Comboboxes need special care.
     nsIComboboxControlFrame* comboBox = do_QueryFrame(scrollFrame);
     if (comboBox) {
       if (comboBox->IsDroppedDown()) {
         // Don't propagate to parent when drop down menu is active.
         return canScroll ? frameToScroll : nullptr;
       }
       // Always propagate when not dropped down (even if focused).
@@ -3165,43 +3386,63 @@ nsEventStateManager::PostHandleEvent(nsP
 
       nsIPresShell *shell = presContext->GetPresShell();
       if (shell) {
         nsRefPtr<nsFrameSelection> frameSelection = shell->FrameSelection();
         frameSelection->SetMouseDownState(false);
       }
     }
     break;
+  case NS_WHEEL_STOP:
+    {
+      MOZ_ASSERT(aEvent->mFlags.mIsTrusted);
+      nsScrollbarsForWheel::MayInactivate();
+    }
+    break;
   case NS_WHEEL_WHEEL:
+  case NS_WHEEL_START:
     {
       MOZ_ASSERT(aEvent->mFlags.mIsTrusted);
 
       if (*aStatus == nsEventStatus_eConsumeNoDefault) {
+        nsScrollbarsForWheel::Inactivate();
         break;
       }
 
       WheelEvent* wheelEvent = static_cast<WheelEvent*>(aEvent);
       switch (WheelPrefs::GetInstance()->ComputeActionFor(wheelEvent)) {
         case WheelPrefs::ACTION_SCROLL: {
-          if (!wheelEvent->deltaX && !wheelEvent->deltaY) {
+          // For scrolling of default action, we should honor the mouse wheel
+          // transaction.
+
+          nsScrollbarsForWheel::PrepareToScrollText(this, aTargetFrame, wheelEvent);
+
+          if (aEvent->message != NS_WHEEL_WHEEL ||
+              (!wheelEvent->deltaX && !wheelEvent->deltaY)) {
             break;
           }
-          // For scrolling of default action, we should honor the mouse wheel
-          // transaction.
+
           nsIScrollableFrame* scrollTarget =
             ComputeScrollTarget(aTargetFrame, wheelEvent,
                                 COMPUTE_DEFAULT_ACTION_TARGET);
+
+          nsScrollbarsForWheel::SetActiveScrollTarget(scrollTarget);
+
+          if (!scrollTarget) {
+            wheelEvent->mViewPortIsOverscrolled = true;
+          }
           wheelEvent->overflowDeltaX = wheelEvent->deltaX;
           wheelEvent->overflowDeltaY = wheelEvent->deltaY;
           WheelPrefs::GetInstance()->
             CancelApplyingUserPrefsFromOverflowDelta(wheelEvent);
           if (scrollTarget) {
             DoScrollText(scrollTarget, wheelEvent);
           } else {
             nsMouseWheelTransaction::EndTransaction();
+            nsScrollbarsForWheel::Inactivate();
           }
           break;
         }
         case WheelPrefs::ACTION_HISTORY: {
           // If this event doesn't cause NS_MOUSE_SCROLL event or the direction
           // is oblique, don't perform history back/forward.
           int32_t intDelta = wheelEvent->GetPreferredIntDelta();
           if (!intDelta) {
--- a/content/events/src/nsEventStateManager.h
+++ b/content/events/src/nsEventStateManager.h
@@ -41,16 +41,17 @@ class TabParent;
 /*
  * Event listener manager
  */
 
 class nsEventStateManager : public nsSupportsWeakReference,
                             public nsIObserver
 {
   friend class nsMouseWheelTransaction;
+  friend class nsScrollbarsForWheel;
 public:
 
   typedef mozilla::TimeStamp TimeStamp;
   typedef mozilla::TimeDuration TimeDuration;
   typedef mozilla::LayoutDeviceIntPoint LayoutDeviceIntPoint;
 
   nsEventStateManager();
   virtual ~nsEventStateManager();
@@ -552,16 +553,22 @@ protected:
       (PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_X_AXIS | START_FROM_PARENT),
     COMPUTE_SCROLLABLE_ANCESTOR_ALONG_Y_AXIS     =
       (PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_Y_AXIS | START_FROM_PARENT)
   };
   nsIScrollableFrame* ComputeScrollTarget(nsIFrame* aTargetFrame,
                                           mozilla::WheelEvent* aEvent,
                                           ComputeScrollTargetOptions aOptions);
 
+  nsIScrollableFrame* ComputeScrollTarget(nsIFrame* aTargetFrame,
+                                          double aDirectionX,
+                                          double aDirectionY,
+                                          mozilla::WheelEvent* aEvent,
+                                          ComputeScrollTargetOptions aOptions);
+
   /**
    * GetScrollAmount() returns the scroll amount in app uints of one line or
    * one page.  If the wheel event scrolls a page, returns the page width and
    * height.  Otherwise, returns line height for both its width and height.
    *
    * @param aScrollableFrame    A frame which will be scrolled by the event.
    *                            The result of ComputeScrollTarget() is
    *                            expected for this value.
--- a/dom/bindings/BindingDeclarations.h
+++ b/dom/bindings/BindingDeclarations.h
@@ -13,20 +13,19 @@
 #ifndef mozilla_dom_BindingDeclarations_h__
 #define mozilla_dom_BindingDeclarations_h__
 
 #include "nsStringGlue.h"
 #include "js/Value.h"
 #include "js/RootingAPI.h"
 #include "mozilla/Maybe.h"
 #include "nsCOMPtr.h"
-#include "nsDOMString.h"
-#include "nsStringBuffer.h"
 #include "nsTArray.h"
 #include "nsAutoPtr.h" // for nsRefPtr member variables
+#include "mozilla/dom/DOMString.h"
 #include "mozilla/dom/OwningNonNull.h"
 
 class nsWrapperCache;
 
 // nsGlobalWindow implements nsWrapperCache, but doesn't always use it. Don't
 // try to use it without fixing that first.
 class nsGlobalWindow;
 
@@ -85,143 +84,16 @@ public:
 
 protected:
   JS::RootedObject mGlobalJSObject;
   JSContext* mCx;
   mutable nsISupports* mGlobalObject;
   mutable nsCOMPtr<nsISupports> mGlobalObjectRef;
 };
 
-/**
- * A class for representing string return values.  This can be either passed to
- * callees that have an nsString or nsAString out param or passed to a callee
- * that actually knows about this class and can work with it.  Such a callee may
- * call SetStringBuffer on this object, but only if it plans to keep holding a
- * strong ref to the stringbuffer!
- *
- * The proper way to store a value in this class is to either to do nothing
- * (which leaves this as an empty string), to call SetStringBuffer with a
- * non-null stringbuffer, to call SetNull(), or to call AsAString() and set the
- * value in the resulting nsString.  These options are mutually exclusive!
- * Don't do more than one of them.
- *
- * The proper way to extract a value is to check IsNull().  If not null, then
- * check HasStringBuffer().  If that's true, check for a zero length, and if the
- * length is nonzero call StringBuffer().  If the length is zero this is the
- * empty string.  If HasStringBuffer() returns false, call AsAString() and get
- * the value from that.
- */
-class MOZ_STACK_CLASS DOMString {
-public:
-  DOMString()
-    : mStringBuffer(nullptr)
-    , mLength(0)
-    , mIsNull(false)
-  {}
-  ~DOMString()
-  {
-    MOZ_ASSERT(mString.empty() || !mStringBuffer,
-               "Shouldn't have both present!");
-  }
-
-  operator nsString&()
-  {
-    return AsAString();
-  }
-
-  nsString& AsAString()
-  {
-    MOZ_ASSERT(!mStringBuffer, "We already have a stringbuffer?");
-    MOZ_ASSERT(!mIsNull, "We're already set as null");
-    if (mString.empty()) {
-      mString.construct();
-    }
-    return mString.ref();
-  }
-
-  bool HasStringBuffer() const
-  {
-    MOZ_ASSERT(mString.empty() || !mStringBuffer,
-               "Shouldn't have both present!");
-    MOZ_ASSERT(!mIsNull, "Caller should have checked IsNull() first");
-    return mString.empty();
-  }
-
-  // Get the stringbuffer.  This can only be called if HasStringBuffer()
-  // returned true and StringBufferLength() is nonzero.  If that's true, it will
-  // never return null.
-  nsStringBuffer* StringBuffer() const
-  {
-    MOZ_ASSERT(!mIsNull, "Caller should have checked IsNull() first");
-    MOZ_ASSERT(HasStringBuffer(),
-               "Don't ask for the stringbuffer if we don't have it");
-    MOZ_ASSERT(StringBufferLength() != 0, "Why are you asking for this?");
-    MOZ_ASSERT(mStringBuffer,
-               "If our length is nonzero, we better have a stringbuffer.");
-    return mStringBuffer;
-  }
-
-  // Get the length of the stringbuffer.  Can only be called if
-  // HasStringBuffer().
-  uint32_t StringBufferLength() const
-  {
-    MOZ_ASSERT(HasStringBuffer(), "Don't call this if there is no stringbuffer");
-    return mLength;
-  }
-
-  void SetStringBuffer(nsStringBuffer* aStringBuffer, uint32_t aLength)
-  {
-    MOZ_ASSERT(mString.empty(), "We already have a string?");
-    MOZ_ASSERT(!mIsNull, "We're already set as null");
-    MOZ_ASSERT(!mStringBuffer, "Setting stringbuffer twice?");
-    MOZ_ASSERT(aStringBuffer, "Why are we getting null?");
-    mStringBuffer = aStringBuffer;
-    mLength = aLength;
-  }
-
-  void SetNull()
-  {
-    MOZ_ASSERT(!mStringBuffer, "Should have no stringbuffer if null");
-    MOZ_ASSERT(mString.empty(), "Should have no string if null");
-    mIsNull = true;
-  }
-
-  bool IsNull() const
-  {
-    MOZ_ASSERT(!mStringBuffer || mString.empty(),
-               "How could we have a stringbuffer and a nonempty string?");
-    return mIsNull || (!mString.empty() && mString.ref().IsVoid());
-  }
-
-  void ToString(nsAString& aString)
-  {
-    if (IsNull()) {
-      SetDOMStringToNull(aString);
-    } else if (HasStringBuffer()) {
-      if (StringBufferLength() == 0) {
-        aString.Truncate();
-      } else {
-        StringBuffer()->ToString(StringBufferLength(), aString);
-      }
-    } else {
-      aString = AsAString();
-    }
-  }
-
-private:
-  // We need to be able to act like a string as needed
-  Maybe<nsAutoString> mString;
-
-  // For callees that know we exist, we can be a stringbuffer/length/null-flag
-  // triple.
-  nsStringBuffer* mStringBuffer;
-  uint32_t mLength;
-  bool mIsNull;
-};
-
 // Class for representing optional arguments.
 template<typename T, typename InternalType>
 class Optional_base
 {
 public:
   Optional_base()
   {}
 
@@ -616,9 +488,9 @@ struct ParentObject {
 
   nsISupports* const mObject;
   nsWrapperCache* const mWrapperCache;
 };
 
 } // namespace dom
 } // namespace mozilla
 
-#endif // mozilla_dom_BindingDeclarations_h__
\ No newline at end of file
+#endif // mozilla_dom_BindingDeclarations_h__
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -2698,18 +2698,17 @@ def getJSToNativeConversionInfo(type, de
         if (defaultValue is not None and
             not isinstance(defaultValue, IDLNullValue)):
             raise TypeError("Can't handle non-null default value here")
         return handleDefault(template, codeToSetNull)
 
     # A helper function for wrapping up the template body for
     # possibly-nullable objecty stuff
     def wrapObjectTemplate(templateBody, type, codeToSetNull, failureCode=None):
-        if isNullOrUndefined:
-            assert type.nullable()
+        if isNullOrUndefined and type.nullable():
             # Just ignore templateBody and set ourselves to null.
             # Note that we don't have to worry about default values
             # here either, since we already examined this value.
             return "%s;" % codeToSetNull
 
         if not isDefinitelyObject:
             # Handle the non-object cases by wrapping up the whole
             # thing in an if cascade.
@@ -3316,19 +3315,16 @@ for (uint32_t i = 0; i < length; ++i) {
 
     if type.isDOMString():
         assert not isEnforceRange and not isClamp
 
         treatAs = {
             "Default": "eStringify",
             "EmptyString": "eEmpty",
             "Null": "eNull",
-            # For Missing it doesn't matter what we use here, since we'll never
-            # call ConvertJSValueToString on undefined in that case.
-            "Missing": "eStringify"
         }
         if type.nullable():
             # For nullable strings null becomes a null string.
             treatNullAs = "Null"
             # For nullable strings undefined becomes a null string unless
             # specified otherwise.
             if treatUndefinedAs == "Default":
                 treatUndefinedAs = "Null"
@@ -3838,21 +3834,18 @@ class CGArgumentConverter(CGThing):
             "declName" : "arg%d" % index,
             "holderName" : ("arg%d" % index) + "_holder",
             "obj" : "obj"
             }
         self.replacementVariables["val"] = string.Template(
             "args[${index}]"
             ).substitute(replacer)
         self.replacementVariables["mutableVal"] = self.replacementVariables["val"]
-        if argument.treatUndefinedAs == "Missing":
-            haveValueCheck = "args.hasDefined(${index})"
-        else:
-            haveValueCheck = "${index} < args.length()"
-        haveValueCheck = string.Template(haveValueCheck).substitute(replacer)
+        haveValueCheck = string.Template(
+            "args.hasDefined(${index})").substitute(replacer)
         self.replacementVariables["haveValue"] = haveValueCheck
         self.descriptorProvider = descriptorProvider
         if self.argument.optional and not self.argument.defaultValue:
             self.argcAndIndex = replacer
         else:
             self.argcAndIndex = None
         self.invalidEnumValueFatal = invalidEnumValueFatal
         self.lenientFloatCode = lenientFloatCode
@@ -4983,25 +4976,16 @@ class CGMethodCall(CGThing):
                 code = (
                     "if (args.length() < %d) {\n"
                     '  return ThrowErrorMessage(cx, MSG_MISSING_ARGUMENTS, "%s");\n'
                     "}" % (requiredArgs, methodName))
                 self.cgRoot.prepend(
                     CGWrapper(CGIndenter(CGGeneric(code)), pre="\n", post="\n"))
             return
 
-        # We don't handle [TreatUndefinedAs=Missing] arguments in overload
-        # resolution yet.
-        for (_, sigArgs) in signatures:
-            for arg in sigArgs:
-                if arg.treatUndefinedAs == "Missing":
-                    raise TypeError("No support for [TreatUndefinedAs=Missing] "
-                                    "handling in overload resolution yet: %s" %
-                                    arg.location)
-
         # Need to find the right overload
         maxArgCount = method.maxArgCount
         allowedArgCounts = method.allowedArgCounts
 
         argCountCases = []
         for argCount in allowedArgCounts:
             possibleSignatures = method.signaturesForArgCount(argCount)
             if len(possibleSignatures) == 1:
@@ -5081,59 +5065,119 @@ class CGMethodCall(CGThing):
                         isNullOrUndefined=False):
                 assert not isDefinitelyObject or not isNullOrUndefined
                 assert isDefinitelyObject or isNullOrUndefined
                 if isDefinitelyObject:
                     failureCode = "break;"
                 else:
                     failureCode = None
                 type = distinguishingType(signature)
-                # The argument at index distinguishingIndex can't possibly
-                # be unset here, because we've already checked that argc is
-                # large enough that we can examine this argument.
+                # The argument at index distinguishingIndex can't possibly be
+                # unset here, because we've already checked that argc is large
+                # enough that we can examine this argument.  But note that we
+                # still want to claim that optional arguments are optional, in
+                # case undefined was passed in.
+                argIsOptional = (distinguishingArgument(signature).optional and
+                                 not distinguishingArgument(signature).defaultValue)
                 testCode = instantiateJSToNativeConversion(
                     getJSToNativeConversionInfo(type, descriptor,
                                                 failureCode=failureCode,
                                                 isDefinitelyObject=isDefinitelyObject,
                                                 isNullOrUndefined=isNullOrUndefined,
+                                                isOptional=argIsOptional,
                                                 sourceDescription=(argDesc % (distinguishingIndex + 1))),
                     {
                         "declName" : "arg%d" % distinguishingIndex,
                         "holderName" : ("arg%d" % distinguishingIndex) + "_holder",
                         "val" : distinguishingArg,
                         "mutableVal" : distinguishingArg,
-                        "obj" : "obj"
-                        })
+                        "obj" : "obj",
+                        "haveValue": "args.hasDefined(%d)" % distinguishingIndex
+                        },
+                    checkForValue=argIsOptional
+                    )
                 caseBody.append(CGIndenter(testCode, indent));
                 # If we got this far, we know we unwrapped to the right
                 # C++ type, so just do the call.  Start conversion with
                 # distinguishingIndex + 1, since we already converted
                 # distinguishingIndex.
                 caseBody.append(CGIndenter(
                         getPerSignatureCall(signature, distinguishingIndex + 1),
                         indent))
 
-            # First check for null or undefined.  That means looking for
+            def hasConditionalConversion(type):
+                """
+                Return whether the argument conversion for this type will be
+                conditional on the type of incoming JS value.  For example, for
+                interface types the conversion is conditional on the incoming
+                value being isObject().
+
+                For the types for which this returns false, we do not have to
+                output extra isUndefined() or isNullOrUndefined() cases, because
+                null/undefined values will just fall through into our
+                unconditional conversion.
+                """
+                if type.isString() or type.isEnum():
+                    return False
+                if type.isBoolean():
+                    distinguishingTypes = (distinguishingType(s) for s in
+                                           possibleSignatures)
+                    return any(t.isString() or t.isEnum() or t.isNumeric()
+                               for t in distinguishingTypes)
+                if type.isNumeric():
+                    distinguishingTypes = (distinguishingType(s) for s in
+                                           possibleSignatures)
+                    return any(t.isString() or t.isEnum()
+                               for t in distinguishingTypes)
+                return True
+
+            def needsNullOrUndefinedCase(type):
+                """
+                Return true if the type needs a special isNullOrUndefined() case
+                """
+                return ((type.nullable() and
+                        hasConditionalConversion(type)) or
+                        type.isDictionary())
+
+            # First check for undefined and optional distinguishing arguments
+            # and output a special branch for that case.  Note that we don't
+            # use distinguishingArgument here because we actualy want to
+            # exclude variadic arguments.  Also note that we skip this check if
+            # we plan to output a isNullOrUndefined() special case for this
+            # argument anyway, since that will subsume our isUndefined() check.
+            # This is safe, because there can be at most one nullable
+            # distinguishing argument, so if we're it we'll definitely get
+            # picked up by the nullable handling.  Also, we can skip this check
+            # if the argument has an unconditional conversion later on.
+            undefSigs = [s for s in possibleSignatures if
+                         distinguishingIndex < len(s[1]) and
+                         s[1][distinguishingIndex].optional and
+                         hasConditionalConversion(s[1][distinguishingIndex].type) and
+                         not needsNullOrUndefinedCase(s[1][distinguishingIndex].type)]
+            # Can't have multiple signatures with an optional argument at the
+            # same index.
+            assert len(undefSigs) < 2
+            if len(undefSigs) > 0:
+                caseBody.append(CGGeneric("if (%s.isUndefined()) {" %
+                                          distinguishingArg))
+                tryCall(undefSigs[0], 2, isNullOrUndefined=True)
+                caseBody.append(CGGeneric("}"))
+
+            # Next, check for null or undefined.  That means looking for
             # nullable arguments at the distinguishing index and outputting a
-            # separate branch for them.  But if the nullable argument is a
-            # primitive, string, or enum, we don't need to do that.  The reason
+            # separate branch for them.  But if the nullable argument has an
+            # unconditional conversion, we don't need to do that.  The reason
             # for that is that at most one argument at the distinguishing index
             # is nullable (since two nullable arguments are not
-            # distinguishable), and all the argument types other than
-            # primitive/string/enum end up inside isObject() checks.  So if our
-            # nullable is a primitive/string/enum it's safe to not output the
-            # extra branch: we'll fall through to conversion for those types,
-            # which correctly handles null as needed, because isObject() will be
-            # false for null and undefined.
+            # distinguishable), and null/undefined values will always fall
+            # through to the unconditional conversion we have, if any, since
+            # they will fail whatever the conditions on the input value are for
+            # our other conversions.
             nullOrUndefSigs = [s for s in possibleSignatures
-                               if ((distinguishingType(s).nullable() and not
-                                    distinguishingType(s).isString() and not
-                                    distinguishingType(s).isEnum() and not
-                                   distinguishingType(s).isPrimitive()) or
-                                   distinguishingType(s).isDictionary())]
+                               if needsNullOrUndefinedCase(distinguishingType(s))]
             # Can't have multiple nullable types here
             assert len(nullOrUndefSigs) < 2
             if len(nullOrUndefSigs) > 0:
                 caseBody.append(CGGeneric("if (%s.isNullOrUndefined()) {" %
                                           distinguishingArg))
                 tryCall(nullOrUndefSigs[0], 2, isNullOrUndefined=True)
                 caseBody.append(CGGeneric("}"))
 
new file mode 100644
--- /dev/null
+++ b/dom/bindings/DOMString.h
@@ -0,0 +1,149 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_DOMString_h
+#define mozilla_dom_DOMString_h
+
+#include "nsStringGlue.h"
+#include "nsStringBuffer.h"
+#include "mozilla/Assertions.h"
+#include "mozilla/Attributes.h"
+#include "mozilla/Maybe.h"
+#include "nsDOMString.h"
+
+namespace mozilla {
+namespace dom {
+
+/**
+ * A class for representing string return values.  This can be either passed to
+ * callees that have an nsString or nsAString out param or passed to a callee
+ * that actually knows about this class and can work with it.  Such a callee may
+ * call SetStringBuffer on this object, but only if it plans to keep holding a
+ * strong ref to the stringbuffer!
+ *
+ * The proper way to store a value in this class is to either to do nothing
+ * (which leaves this as an empty string), to call SetStringBuffer with a
+ * non-null stringbuffer, to call SetNull(), or to call AsAString() and set the
+ * value in the resulting nsString.  These options are mutually exclusive!
+ * Don't do more than one of them.
+ *
+ * The proper way to extract a value is to check IsNull().  If not null, then
+ * check HasStringBuffer().  If that's true, check for a zero length, and if the
+ * length is nonzero call StringBuffer().  If the length is zero this is the
+ * empty string.  If HasStringBuffer() returns false, call AsAString() and get
+ * the value from that.
+ */
+class MOZ_STACK_CLASS DOMString {
+public:
+  DOMString()
+    : mStringBuffer(nullptr)
+    , mLength(0)
+    , mIsNull(false)
+  {}
+  ~DOMString()
+  {
+    MOZ_ASSERT(mString.empty() || !mStringBuffer,
+               "Shouldn't have both present!");
+  }
+
+  operator nsString&()
+  {
+    return AsAString();
+  }
+
+  nsString& AsAString()
+  {
+    MOZ_ASSERT(!mStringBuffer, "We already have a stringbuffer?");
+    MOZ_ASSERT(!mIsNull, "We're already set as null");
+    if (mString.empty()) {
+      mString.construct();
+    }
+    return mString.ref();
+  }
+
+  bool HasStringBuffer() const
+  {
+    MOZ_ASSERT(mString.empty() || !mStringBuffer,
+               "Shouldn't have both present!");
+    MOZ_ASSERT(!mIsNull, "Caller should have checked IsNull() first");
+    return mString.empty();
+  }
+
+  // Get the stringbuffer.  This can only be called if HasStringBuffer()
+  // returned true and StringBufferLength() is nonzero.  If that's true, it will
+  // never return null.
+  nsStringBuffer* StringBuffer() const
+  {
+    MOZ_ASSERT(!mIsNull, "Caller should have checked IsNull() first");
+    MOZ_ASSERT(HasStringBuffer(),
+               "Don't ask for the stringbuffer if we don't have it");
+    MOZ_ASSERT(StringBufferLength() != 0, "Why are you asking for this?");
+    MOZ_ASSERT(mStringBuffer,
+               "If our length is nonzero, we better have a stringbuffer.");
+    return mStringBuffer;
+  }
+
+  // Get the length of the stringbuffer.  Can only be called if
+  // HasStringBuffer().
+  uint32_t StringBufferLength() const
+  {
+    MOZ_ASSERT(HasStringBuffer(), "Don't call this if there is no stringbuffer");
+    return mLength;
+  }
+
+  void SetStringBuffer(nsStringBuffer* aStringBuffer, uint32_t aLength)
+  {
+    MOZ_ASSERT(mString.empty(), "We already have a string?");
+    MOZ_ASSERT(!mIsNull, "We're already set as null");
+    MOZ_ASSERT(!mStringBuffer, "Setting stringbuffer twice?");
+    MOZ_ASSERT(aStringBuffer, "Why are we getting null?");
+    mStringBuffer = aStringBuffer;
+    mLength = aLength;
+  }
+
+  void SetNull()
+  {
+    MOZ_ASSERT(!mStringBuffer, "Should have no stringbuffer if null");
+    MOZ_ASSERT(mString.empty(), "Should have no string if null");
+    mIsNull = true;
+  }
+
+  bool IsNull() const
+  {
+    MOZ_ASSERT(!mStringBuffer || mString.empty(),
+               "How could we have a stringbuffer and a nonempty string?");
+    return mIsNull || (!mString.empty() && mString.ref().IsVoid());
+  }
+
+  void ToString(nsAString& aString)
+  {
+    if (IsNull()) {
+      SetDOMStringToNull(aString);
+    } else if (HasStringBuffer()) {
+      if (StringBufferLength() == 0) {
+        aString.Truncate();
+      } else {
+        StringBuffer()->ToString(StringBufferLength(), aString);
+      }
+    } else {
+      aString = AsAString();
+    }
+  }
+
+private:
+  // We need to be able to act like a string as needed
+  Maybe<nsAutoString> mString;
+
+  // For callees that know we exist, we can be a stringbuffer/length/null-flag
+  // triple.
+  nsStringBuffer* mStringBuffer;
+  uint32_t mLength;
+  bool mIsNull;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_DOMString_h
--- a/dom/bindings/Nullable.h
+++ b/dom/bindings/Nullable.h
@@ -76,21 +76,16 @@ public:
     return Equals(aOtherNullable);
   }
 
   bool operator!=(const Nullable<T>& aOtherNullable) const
   {
     return !Equals(aOtherNullable);
   }
 
-  operator bool() const
-  {
-    return !mIsNull;
-  }
-
   // Make it possible to use a const Nullable of an array type with other
   // array types.
   template<typename U>
   operator const Nullable< nsTArray<U> >&() const {
     // Make sure that T is ok to reinterpret to nsTArray<U>
     const nsTArray<U>& arr = mValue;
     (void)arr;
     return *reinterpret_cast<const Nullable< nsTArray<U> >*>(this);
--- a/dom/bindings/moz.build
+++ b/dom/bindings/moz.build
@@ -14,16 +14,17 @@ EXPORTS.mozilla.dom += [
     'AtomList.h',
     'BindingDeclarations.h',
     'BindingUtils.h',
     'CallbackFunction.h',
     'CallbackInterface.h',
     'CallbackObject.h',
     'DOMJSClass.h',
     'DOMJSProxyHandler.h',
+    'DOMString.h',
     'Date.h',
     'Errors.msg',
     'Exceptions.h',
     'JSSlots.h',
     'NonRefcountedDOMObject.h',
     'Nullable.h',
     'OwningNonNull.h',
     'PrimitiveConversions.h',
--- a/dom/bindings/parser/WebIDL.py
+++ b/dom/bindings/parser/WebIDL.py
@@ -396,22 +396,17 @@ class IDLObjectWithIdentifier(IDLObject)
                     raise WebIDLError("[TreatNullAs] must take the identifier "
                                       "'EmptyString', not '%s'" % value,
                                       [self.location])
                 self.treatNullAs = value
             elif identifier == "TreatUndefinedAs":
                 if isDictionaryMember:
                     raise WebIDLError("[TreatUndefinedAs] is not allowed for "
                                       "dictionary members", [self.location])
-                if value == 'Missing':
-                    if not isOptional:
-                        raise WebIDLError("[TreatUndefinedAs=Missing] is only "
-                                          "allowed on optional arguments",
-                                          [self.location])
-                elif value == 'Null':
+                if value == 'Null':
                     if not self.type.isDOMString():
                         raise WebIDLError("[TreatUndefinedAs=Null] is only "
                                           "allowed on arguments or "
                                           "attributes whose type is "
                                           "DOMString or DOMString?",
                                           [self.location])
                     if not self.type.nullable():
                         raise WebIDLError("[TreatUndefinedAs=Null] is only "
@@ -421,18 +416,18 @@ class IDLObjectWithIdentifier(IDLObject)
                     if not self.type.isDOMString():
                         raise WebIDLError("[TreatUndefinedAs=EmptyString] "
                                           "is only allowed on arguments or "
                                           "attributes whose type is "
                                           "DOMString or DOMString?",
                                           [self.location])
                 else:
                     raise WebIDLError("[TreatUndefinedAs] must take the "
-                                      "identifiers EmptyString or Null or "
-                                      "Missing", [self.location])
+                                      "identifiers EmptyString or Null",
+                                      [self.location])
                 self.treatUndefinedAs = value
             else:
                 unhandledAttrs.append(attr)
 
         return unhandledAttrs
 
 class IDLObjectWithScope(IDLObjectWithIdentifier, IDLScope):
     def __init__(self, location, parentScope, identifier):
@@ -3138,35 +3133,32 @@ class IDLMethod(IDLInterfaceMember, IDLS
         return self
 
     def signatures(self):
         return [(overload.returnType, overload.arguments) for overload in
                 self._overloads]
 
     def finish(self, scope):
         for overload in self._overloads:
-            inOptionalArguments = False
             variadicArgument = None
 
             arguments = overload.arguments
             for (idx, argument) in enumerate(arguments):
-                if argument.isComplete():
-                    continue
-
-                argument.complete(scope)
+                if not argument.isComplete():
+                    argument.complete(scope)
                 assert argument.type.isComplete()
 
                 if (argument.type.isDictionary() or
                     (argument.type.isUnion() and
                      argument.type.unroll().hasDictionaryType)):
                     # Dictionaries and unions containing dictionaries at the
                     # end of the list or followed by optional arguments must be
                     # optional.
                     if (not argument.optional and
-                        (idx == len(arguments) - 1 or arguments[idx+1].optional)):
+                        all(arg.optional for arg in arguments[idx+1:])):
                         raise WebIDLError("Dictionary argument or union "
                                           "argument containing a dictionary "
                                           "not followed by a required argument "
                                           "must be optional",
                                           [argument.location])
 
                     # An argument cannot be a Nullable Dictionary
                     if argument.type.nullable():
@@ -3174,23 +3166,16 @@ class IDLMethod(IDLInterfaceMember, IDLS
                                           "dictionary or nullable union "
                                           "containing a dictionary",
                                           [argument.location])
 
                 # Only the last argument can be variadic
                 if variadicArgument:
                     raise WebIDLError("Variadic argument is not last argument",
                                       [variadicArgument.location])
-                # Once we see an optional argument, there can't be any non-optional
-                # arguments.
-                if inOptionalArguments and not argument.optional:
-                    raise WebIDLError("Non-optional argument after optional "
-                                      "arguments",
-                                      [argument.location])
-                inOptionalArguments = argument.optional
                 if argument.variadic:
                     variadicArgument = argument
 
             returnType = overload.returnType
             if returnType.isComplete():
                 continue
 
             type = returnType.complete(scope)
@@ -3225,17 +3210,17 @@ class IDLMethod(IDLInterfaceMember, IDLS
                             (self.identifier.name, argCount, idx,
                              distinguishingIndex),
                             [self.location, overload.location])
 
     def overloadsForArgCount(self, argc):
         return [overload for overload in self._overloads if
                 len(overload.arguments) == argc or
                 (len(overload.arguments) > argc and
-                 overload.arguments[argc].optional) or
+                 all(arg.optional for arg in overload.arguments[argc:])) or
                 (len(overload.arguments) < argc and
                  len(overload.arguments) > 0 and
                  overload.arguments[-1].variadic)]
 
     def signaturesForArgCount(self, argc):
         return [(overload.returnType, overload.arguments) for overload
                 in self.overloadsForArgCount(argc)]
 
@@ -4055,31 +4040,16 @@ class Parser(Tokenizer):
         if stringifier:
             if len(arguments) != 0:
                 raise WebIDLError("stringifier has wrong number of arguments",
                                   [self.getLocation(p, 2)])
             if not returnType.isDOMString():
                 raise WebIDLError("stringifier must have DOMString return type",
                                   [self.getLocation(p, 2)])
 
-        inOptionalArguments = False
-        variadicArgument = False
-        for argument in arguments:
-            # Only the last argument can be variadic
-            if variadicArgument:
-                raise WebIDLError("Only the last argument can be variadic",
-                                  [variadicArgument.location])
-            # Once we see an optional argument, there can't be any non-optional
-            # arguments.
-            if inOptionalArguments and not argument.optional:
-                raise WebIDLError("Cannot have a non-optional argument following an optional argument",
-                                  [argument.location])
-            inOptionalArguments = argument.optional
-            variadicArgument = argument if argument.variadic else None
-
         # identifier might be None.  This is only permitted for special methods.
         if not identifier:
             if not getter and not setter and not creator and \
                not deleter and not legacycaller and not stringifier:
                 raise WebIDLError("Identifier required for non-special methods",
                                   [self.getLocation(p, 2)])
 
             location = BuiltinLocation("<auto-generated-identifier>")
--- a/dom/bindings/parser/tests/test_dictionary.py
+++ b/dom/bindings/parser/tests/test_dictionary.py
@@ -173,16 +173,33 @@ def WebIDLTest(parser, harness):
 
     parser = parser.reset()
     threw = False
     try:
         parser.parse("""
             dictionary A {
             };
             interface X {
+              void doFoo(A arg1, optional long arg2, long arg3);
+            };
+        """)
+        results = parser.finish()
+    except:
+        threw = True
+
+    harness.ok(not threw,
+               "Dictionary arg followed by non-optional arg doesn't have to be optional")
+
+    parser = parser.reset()
+    threw = False
+    try:
+        parser.parse("""
+            dictionary A {
+            };
+            interface X {
               void doFoo((A or DOMString) arg1, optional long arg2);
             };
         """)
         results = parser.finish()
     except:
         threw = True
 
     harness.ok(threw,
--- a/dom/bindings/parser/tests/test_optional_constraints.py
+++ b/dom/bindings/parser/tests/test_optional_constraints.py
@@ -6,19 +6,19 @@ def WebIDLTest(parser, harness):
               void foo(optional byte arg1, byte arg2);
             };
         """)
 
         results = parser.finish()
     except:
         threw = True
 
-    harness.ok(threw,
-               "Should have thrown on non-optional argument following optional "
-               "argument.")
+    harness.ok(not threw,
+               "Should not have thrown on non-optional argument following "
+               "optional argument.")
 
     parser = parser.reset()
     parser.parse("""
         interface OptionalConstraints2 {
           void foo(optional byte arg1 = 1, optional byte arg2 = 2,
                    optional byte arg3, optional byte arg4 = 4,
                    optional byte arg5, optional byte arg6 = 9);
         };
--- a/dom/bindings/parser/tests/test_overload.py
+++ b/dom/bindings/parser/tests/test_overload.py
@@ -6,29 +6,31 @@ def WebIDLTest(parser, harness):
           void basic();
           void basic(long arg1);
           boolean abitharder(TestOverloads foo);
           boolean abitharder(boolean foo);
           void abitharder(ArrayBuffer? foo);
           void withVariadics(long... numbers);
           void withVariadics(TestOverloads iface);
           void withVariadics(long num, TestOverloads iface);
+          void optionalTest();
+          void optionalTest(optional long num1, long num2);
         };
     """)
 
     results = parser.finish()
 
     harness.ok(True, "TestOverloads interface parsed without error.")
     harness.check(len(results), 1, "Should be one production.")
     iface = results[0]
     harness.ok(isinstance(iface, WebIDL.IDLInterface),
                "Should be an IDLInterface")
     harness.check(iface.identifier.QName(), "::TestOverloads", "Interface has the right QName")
     harness.check(iface.identifier.name, "TestOverloads", "Interface has the right name")
-    harness.check(len(iface.members), 3, "Expect %s members" % 3)
+    harness.check(len(iface.members), 4, "Expect %s members" % 4)
 
     member = iface.members[0]
     harness.check(member.identifier.QName(), "::TestOverloads::basic", "Method has the right QName")
     harness.check(member.identifier.name, "basic", "Method has the right name")
     harness.check(member.hasOverloads(), True, "Method has overloads")
 
     signatures = member.signatures()
     harness.check(len(signatures), 2, "Method should have 2 signatures")
@@ -43,8 +45,16 @@ def WebIDLTest(parser, harness):
     harness.check(len(argumentSet), 1, "Expect an argument set with one argument")
 
     argument = argumentSet[0]
     harness.ok(isinstance(argument, WebIDL.IDLArgument),
                "Should be an IDLArgument")
     harness.check(argument.identifier.QName(), "::TestOverloads::basic::arg1", "Argument has the right QName")
     harness.check(argument.identifier.name, "arg1", "Argument has the right name")
     harness.check(str(argument.type), "Long", "Argument has the right type")
+
+    member = iface.members[3]
+    harness.check(len(member.overloadsForArgCount(0)), 1,
+                  "Only one overload for no args")
+    harness.check(len(member.overloadsForArgCount(1)), 0,
+                  "No overloads for one arg")
+    harness.check(len(member.overloadsForArgCount(2)), 1,
+                  "Only one overload for two args")
--- a/dom/bindings/parser/tests/test_variadic_constraints.py
+++ b/dom/bindings/parser/tests/test_variadic_constraints.py
@@ -1,52 +1,63 @@
 def WebIDLTest(parser, harness):
     threw = False
     try:
-        results = parser.parse("""
+        parser.parse("""
             interface VariadicConstraints1 {
               void foo(byte... arg1, byte arg2);
             };
         """)
-
-    except:
-        threw = True
-
-    harness.ok(threw, "Should have thrown.")
-
-    threw = False
-    try:
-        results = parser.parse("""
-            interface VariadicConstraints2 {
-              void foo(byte... arg1, optional byte arg2);
-            };
-        """)
+        results = parser.finish()
 
     except:
         threw = True
 
-    harness.ok(threw, "Should have thrown.")
+    harness.ok(threw,
+               "Should have thrown on variadic argument followed by required "
+               "argument.")
 
+    parser = parser.reset()
     threw = False
     try:
-        results = parser.parse("""
+        parser.parse("""
+            interface VariadicConstraints2 {
+              void foo(byte... arg1, optional byte arg2);
+            };
+        """)
+        results = parser.finish();
+    except:
+        threw = True
+
+    harness.ok(threw,
+               "Should have thrown on variadic argument followed by optional "
+               "argument.")
+
+    parser = parser.reset()
+    threw = False
+    try:
+        parser.parse("""
             interface VariadicConstraints3 {
               void foo(optional byte... arg1);
             };
         """)
+        results = parser.finish()
 
     except:
         threw = True
 
-    harness.ok(threw, "Should have thrown.")
+    harness.ok(threw,
+               "Should have thrown on variadic argument explicitly flagged as "
+               "optional.")
 
+    parser = parser.reset()
     threw = False
     try:
-        results = parser.parse("""
+        parser.parse("""
             interface VariadicConstraints4 {
               void foo(byte... arg1 = 0);
             };
         """)
-
+        results = parser.finish()
     except:
         threw = True
 
     harness.ok(threw, "Should have thrown on variadic argument with default value.")
--- a/dom/bindings/test/TestBindingHeader.h
+++ b/dom/bindings/test/TestBindingHeader.h
@@ -156,19 +156,19 @@ public:
 
   // Integer types
   int8_t ReadonlyByte();
   int8_t WritableByte();
   void SetWritableByte(int8_t);
   void PassByte(int8_t);
   int8_t ReceiveByte();
   void PassOptionalByte(const Optional<int8_t>&);
-  void PassOptionalUndefinedMissingByte(const Optional<int8_t>&);
+  void PassOptionalByteBeforeRequired(const Optional<int8_t>&, int8_t);
   void PassOptionalByteWithDefault(int8_t);
-  void PassOptionalUndefinedMissingByteWithDefault(int8_t);
+  void PassOptionalByteWithDefaultBeforeRequired(int8_t, int8_t);
   void PassNullableByte(const Nullable<int8_t>&);
   void PassOptionalNullableByte(const Optional< Nullable<int8_t> >&);
   void PassVariadicByte(const Sequence<int8_t>&);
 
   int16_t ReadonlyShort();
   int16_t WritableShort();
   void SetWritableShort(int16_t);
   void PassShort(int16_t);
@@ -405,19 +405,17 @@ public:
   void PassVariadicTypedArray(const Sequence<Float32Array>&);
   void PassVariadicNullableTypedArray(const Sequence<Nullable<Float32Array> >&);
   JSObject* ReceiveUint8Array(JSContext*);
 
   // DOMString types
   void PassString(const nsAString&);
   void PassNullableString(const nsAString&);
   void PassOptionalString(const Optional<nsAString>&);
-  void PassOptionalUndefinedMissingString(const Optional<nsAString>&);
   void PassOptionalStringWithDefaultValue(const nsAString&);
-  void PassOptionalUndefinedMissingStringWithDefaultValue(const nsAString&);
   void PassOptionalNullableString(const Optional<nsAString>&);
   void PassOptionalNullableStringWithDefaultValue(const nsAString&);
   void PassVariadicString(const Sequence<nsString>&);
 
   // ByteString types
   void PassByteString(const nsCString&);
   void PassNullableByteString(const nsCString&);
   void PassOptionalByteString(const Optional<nsCString>&);
@@ -626,16 +624,32 @@ public:
   void Overload5(TestEnum);
   void Overload6(int32_t);
   void Overload6(bool);
   void Overload7(int32_t);
   void Overload7(bool);
   void Overload7(const nsCString&);
   void Overload8(int32_t);
   void Overload8(TestInterface&);
+  void Overload9(const Nullable<int32_t>&);
+  void Overload9(const nsAString&);
+  void Overload10(const Nullable<int32_t>&);
+  void Overload10(JSContext*, JS::Handle<JSObject*>);
+  void Overload11(int32_t);
+  void Overload11(const nsAString&);
+  void Overload12(int32_t);
+  void Overload12(const Nullable<bool>&);
+  void Overload13(const Nullable<int32_t>&);
+  void Overload13(bool);
+  void Overload14(const Optional<int32_t>&);
+  void Overload14(TestInterface&);
+  void Overload15(int32_t);
+  void Overload15(const Optional<NonNull<TestInterface> >&);
+  void Overload16(int32_t);
+  void Overload16(const Optional<TestInterface*>&);
 
   // Variadic handling
   void PassVariadicThirdArg(const nsAString&, int32_t,
                             const Sequence<OwningNonNull<TestInterface> >&);
 
   // Conditionally exposed methods/attributes
   bool Prefable1();
   bool Prefable2();
--- a/dom/bindings/test/TestCodeGen.webidl
+++ b/dom/bindings/test/TestCodeGen.webidl
@@ -113,19 +113,19 @@ interface OnlyForUseInConstructor {
 interface TestInterface {
   // Integer types
   // XXXbz add tests for throwing versions of all the integer stuff
   readonly attribute byte readonlyByte;
   attribute byte writableByte;
   void passByte(byte arg);
   byte receiveByte();
   void passOptionalByte(optional byte arg);
-  void passOptionalUndefinedMissingByte([TreatUndefinedAs=Missing] optional byte arg);
+  void passOptionalByteBeforeRequired(optional byte arg1, byte arg2);
   void passOptionalByteWithDefault(optional byte arg = 0);
-  void passOptionalUndefinedMissingByteWithDefault([TreatUndefinedAs=Missing] optional byte arg = 0);
+  void passOptionalByteWithDefaultBeforeRequired(optional byte arg1 = 0, byte arg2);
   void passNullableByte(byte? arg);
   void passOptionalNullableByte(optional byte? arg);
   void passVariadicByte(byte... arg);
 
   readonly attribute short readonlyShort;
   attribute short writableShort;
   void passShort(short arg);
   short receiveShort();
@@ -360,19 +360,17 @@ interface TestInterface {
   void passVariadicTypedArray(Float32Array... arg);
   void passVariadicNullableTypedArray(Float32Array?... arg);
   Uint8Array receiveUint8Array();
 
   // DOMString types
   void passString(DOMString arg);
   void passNullableString(DOMString? arg);
   void passOptionalString(optional DOMString arg);
-  void passOptionalUndefinedMissingString([TreatUndefinedAs=Missing] optional DOMString arg);
   void passOptionalStringWithDefaultValue(optional DOMString arg = "abc");
-  void passOptionalUndefinedMissingStringWithDefaultValue([TreatUndefinedAs=Missing] optional DOMString arg = "abc");
   void passOptionalNullableString(optional DOMString? arg);
   void passOptionalNullableStringWithDefaultValue(optional DOMString? arg = null);
   void passVariadicString(DOMString... arg);
 
   // ByteString types
   void passByteString(ByteString arg);
   void passNullableByteString(ByteString? arg);
   void passOptionalByteString(optional ByteString arg);
@@ -576,16 +574,32 @@ interface TestInterface {
   void overload5(TestEnum arg);
   void overload6(long arg);
   void overload6(boolean arg);
   void overload7(long arg);
   void overload7(boolean arg);
   void overload7(ByteString arg);
   void overload8(long arg);
   void overload8(TestInterface arg);
+  void overload9(long? arg);
+  void overload9(DOMString arg);
+  void overload10(long? arg);
+  void overload10(object arg);
+  void overload11(long arg);
+  void overload11(DOMString? arg);
+  void overload12(long arg);
+  void overload12(boolean? arg);
+  void overload13(long? arg);
+  void overload13(boolean arg);
+  void overload14(optional long arg);
+  void overload14(TestInterface arg);
+  void overload15(long arg);
+  void overload15(optional TestInterface arg);
+  void overload16(long arg);
+  void overload16(optional TestInterface? arg);
 
   // Variadic handling
   void passVariadicThirdArg(DOMString arg1, long arg2, TestInterface... arg3);
 
   // Conditionally exposed methods/attributes
   [Pref="abc.def"]
   readonly attribute boolean prefable1;
   [Pref="abc.def"]
--- a/dom/bindings/test/TestExampleGen.webidl
+++ b/dom/bindings/test/TestExampleGen.webidl
@@ -18,19 +18,19 @@
 interface TestExampleInterface {
   // Integer types
   // XXXbz add tests for throwing versions of all the integer stuff
   readonly attribute byte readonlyByte;
   attribute byte writableByte;
   void passByte(byte arg);
   byte receiveByte();
   void passOptionalByte(optional byte arg);
-  void passOptionalUndefinedMissingByte([TreatUndefinedAs=Missing] optional byte arg);
+  void passOptionalByteBeforeRequired(optional byte arg1, byte arg2);
   void passOptionalByteWithDefault(optional byte arg = 0);
-  void passOptionalUndefinedMissingByteWithDefault([TreatUndefinedAs=Missing] optional byte arg = 0);
+  void passOptionalByteWithDefaultBeforeRequired(optional byte arg1 = 0, byte arg2);
   void passNullableByte(byte? arg);
   void passOptionalNullableByte(optional byte? arg);
   void passVariadicByte(byte... arg);
 
   readonly attribute short readonlyShort;
   attribute short writableShort;
   void passShort(short arg);
   short receiveShort();
@@ -258,19 +258,17 @@ interface TestExampleInterface {
   void passVariadicTypedArray(Float32Array... arg);
   void passVariadicNullableTypedArray(Float32Array?... arg);
   Uint8Array receiveUint8Array();
 
   // DOMString types
   void passString(DOMString arg);
   void passNullableString(DOMString? arg);
   void passOptionalString(optional DOMString arg);
-  void passOptionalUndefinedMissingString([TreatUndefinedAs=Missing] optional DOMString arg);
   void passOptionalStringWithDefaultValue(optional DOMString arg = "abc");
-  void passOptionalUndefinedMissingStringWithDefaultValue([TreatUndefinedAs=Missing] optional DOMString arg = "abc");
   void passOptionalNullableString(optional DOMString? arg);
   void passOptionalNullableStringWithDefaultValue(optional DOMString? arg = null);
   void passVariadicString(DOMString... arg);
 
   // ByteString types
   void passByteString(ByteString arg);
   void passNullableByteString(ByteString? arg);
   void passOptionalByteString(optional ByteString arg);
@@ -473,16 +471,32 @@ interface TestExampleInterface {
   void overload5(TestEnum arg);
   void overload6(long arg);
   void overload6(boolean arg);
   void overload7(long arg);
   void overload7(boolean arg);
   void overload7(ByteString arg);
   void overload8(long arg);
   void overload8(TestInterface arg);
+  void overload9(long? arg);
+  void overload9(DOMString arg);
+  void overload10(long? arg);
+  void overload10(object arg);
+  void overload11(long arg);
+  void overload11(DOMString? arg);
+  void overload12(long arg);
+  void overload12(boolean? arg);
+  void overload13(long? arg);
+  void overload13(boolean arg);
+  void overload14(optional long arg);
+  void overload14(TestInterface arg);
+  void overload15(long arg);
+  void overload15(optional TestInterface arg);
+  void overload16(long arg);
+  void overload16(optional TestInterface? arg);
 
   // Variadic handling
   void passVariadicThirdArg(DOMString arg1, long arg2, TestInterface... arg3);
 
   // Conditionally exposed methods/attributes
   [Pref="abc.def"]
   readonly attribute boolean prefable1;
   [Pref="abc.def"]
--- a/dom/bindings/test/TestJSImplGen.webidl
+++ b/dom/bindings/test/TestJSImplGen.webidl
@@ -30,19 +30,19 @@ enum MyTestEnum {
 interface TestJSImplInterface {
   // Integer types
   // XXXbz add tests for throwing versions of all the integer stuff
   readonly attribute byte readonlyByte;
   attribute byte writableByte;
   void passByte(byte arg);
   byte receiveByte();
   void passOptionalByte(optional byte arg);
-  void passOptionalUndefinedMissingByte([TreatUndefinedAs=Missing] optional byte arg);
+  void passOptionalByteBeforeRequired(optional byte arg1, byte arg2);
   void passOptionalByteWithDefault(optional byte arg = 0);
-  void passOptionalUndefinedMissingByteWithDefault([TreatUndefinedAs=Missing] optional byte arg = 0);
+  void passOptionalByteWithDefaultBeforeRequired(optional byte arg1 = 0, byte arg2);
   void passNullableByte(byte? arg);
   void passOptionalNullableByte(optional byte? arg);
   void passVariadicByte(byte... arg);
 
   readonly attribute short readonlyShort;
   attribute short writableShort;
   void passShort(short arg);
   short receiveShort();
@@ -280,19 +280,17 @@ interface TestJSImplInterface {
   //void passVariadicTypedArray(Float32Array... arg);
   //void passVariadicNullableTypedArray(Float32Array?... arg);
   //Uint8Array receiveUint8Array();
 
   // DOMString types
   void passString(DOMString arg);
   void passNullableString(DOMString? arg);
   void passOptionalString(optional DOMString arg);
-  void passOptionalUndefinedMissingString([TreatUndefinedAs=Missing] optional DOMString arg);
   void passOptionalStringWithDefaultValue(optional DOMString arg = "abc");
-  void passOptionalUndefinedMissingStringWithDefaultValue([TreatUndefinedAs=Missing] optional DOMString arg = "abc");
   void passOptionalNullableString(optional DOMString? arg);
   void passOptionalNullableStringWithDefaultValue(optional DOMString? arg = null);
   void passVariadicString(DOMString... arg);
 
   // ByteString types
   void passByteString(ByteString arg);
   void passNullableByteString(ByteString? arg);
   void passOptionalByteString(optional ByteString arg);
@@ -501,16 +499,32 @@ interface TestJSImplInterface {
   void overload5(MyTestEnum arg);
   void overload6(long arg);
   void overload6(boolean arg);
   void overload7(long arg);
   void overload7(boolean arg);
   void overload7(ByteString arg);
   void overload8(long arg);
   void overload8(TestJSImplInterface arg);
+  void overload9(long? arg);
+  void overload9(DOMString arg);
+  void overload10(long? arg);
+  void overload10(object arg);
+  void overload11(long arg);
+  void overload11(DOMString? arg);
+  void overload12(long arg);
+  void overload12(boolean? arg);
+  void overload13(long? arg);
+  void overload13(boolean arg);
+  void overload14(optional long arg);
+  void overload14(TestInterface arg);
+  void overload15(long arg);
+  void overload15(optional TestInterface arg);
+  void overload16(long arg);
+  void overload16(optional TestInterface? arg);
 
   // Variadic handling
   void passVariadicThirdArg(DOMString arg1, long arg2, TestJSImplInterface... arg3);
 
   // Miscellania
   [LenientThis] attribute long attrWithLenientThis;
   // FIXME: Bug 863954 Unforgeable things get all confused when
   // non-JS-implemented interfaces inherit from JS-implemented ones or vice
--- a/dom/imptests/html/dom/nodes/test_DOMImplementation-createHTMLDocument.html
+++ b/dom/imptests/html/dom/nodes/test_DOMImplementation-createHTMLDocument.html
@@ -13,27 +13,31 @@
 function checkDoc(title, expectedtitle, normalizedtitle) {
   test(function() {
     var doc = document.implementation.createHTMLDocument(title);
     assert_equals(doc.doctype.name, "html")
     assert_equals(doc.doctype.publicId, "")
     assert_equals(doc.doctype.systemId, "")
     assert_equals(doc.documentElement.localName, "html")
     assert_equals(doc.documentElement.firstChild.localName, "head")
-    assert_equals(doc.documentElement.firstChild.childNodes.length, 1)
-    assert_equals(doc.documentElement.firstChild.firstChild.localName, "title")
-    assert_equals(doc.documentElement.firstChild.firstChild.firstChild.data,
-    expectedtitle)
+    if (title !== undefined) {
+      assert_equals(doc.documentElement.firstChild.childNodes.length, 1)
+      assert_equals(doc.documentElement.firstChild.firstChild.localName, "title")
+      assert_equals(doc.documentElement.firstChild.firstChild.firstChild.data,
+                    expectedtitle)
+    } else {
+      assert_equals(doc.documentElement.firstChild.childNodes.length, 0)
+    }
     assert_equals(doc.documentElement.lastChild.localName, "body")
     assert_equals(doc.documentElement.lastChild.childNodes.length, 0)
   })
 }
 checkDoc("", "", "")
 checkDoc(null, "null", "null")
-checkDoc(undefined, "undefined", "undefined")
+checkDoc(undefined, "", "")
 checkDoc("foo  bar baz", "foo  bar baz", "foo bar baz")
 checkDoc("foo\t\tbar baz", "foo\t\tbar baz", "foo bar baz")
 checkDoc("foo\n\nbar baz", "foo\n\nbar baz", "foo bar baz")
 checkDoc("foo\f\fbar baz", "foo\f\fbar baz", "foo bar baz")
 checkDoc("foo\r\rbar baz", "foo\r\rbar baz", "foo bar baz")
 
 test(function() {
   var doc = document.implementation.createHTMLDocument();
--- a/dom/imptests/html/html/dom/documents/dta/test_document.title-07.html
+++ b/dom/imptests/html/html/dom/documents/dta/test_document.title-07.html
@@ -7,15 +7,15 @@
 function checkDoc(title, expectedtitle, normalizedtitle) {
   test(function() {
     var doc = document.implementation.createHTMLDocument(title);
     assert_equals(doc.title, normalizedtitle)
   })
 }
 checkDoc("", "", "")
 checkDoc(null, "null", "null")
-checkDoc(undefined, "undefined", "undefined")
+checkDoc(undefined, "", "")
 checkDoc("foo  bar baz", "foo  bar baz", "foo bar baz")
 checkDoc("foo\t\tbar baz", "foo\t\tbar baz", "foo bar baz")
 checkDoc("foo\n\nbar baz", "foo\n\nbar baz", "foo bar baz")
 checkDoc("foo\f\fbar baz", "foo\f\fbar baz", "foo bar baz")
 checkDoc("foo\r\rbar baz", "foo\r\rbar baz", "foo bar baz")
 </script>
--- a/dom/quota/QuotaManager.cpp
+++ b/dom/quota/QuotaManager.cpp
@@ -2797,17 +2797,17 @@ QuotaManager::RunSynchronizedOp(nsIOffli
 SynchronizedOp*
 QuotaManager::FindSynchronizedOp(const nsACString& aPattern,
                                  Nullable<PersistenceType> aPersistenceType,
                                  nsISupports* aId)
 {
   for (uint32_t index = 0; index < mSynchronizedOps.Length(); index++) {
     const nsAutoPtr<SynchronizedOp>& currentOp = mSynchronizedOps[index];
     if (PatternMatchesOrigin(aPattern, currentOp->mOriginOrPattern) &&
-        (!currentOp->mPersistenceType ||
+        (currentOp->mPersistenceType.IsNull() ||
          currentOp->mPersistenceType == aPersistenceType) &&
         (!currentOp->mId || currentOp->mId == aId)) {
       return currentOp;
     }
   }
 
   return nullptr;
 }
@@ -3062,28 +3062,28 @@ QuotaManager::CollectOriginsForEviction(
   // Collect active origins first.
   OriginCollection originCollection;
 
   // Add patterns and origins that have running or pending synchronized ops.
   // (add patterns first to reduce redundancy in the origin collection).
   uint32_t index;
   for (index = 0; index < mSynchronizedOps.Length(); index++) {
     nsAutoPtr<SynchronizedOp>& op = mSynchronizedOps[index];
-    if (!op->mPersistenceType ||
+    if (op->mPersistenceType.IsNull() ||
         op->mPersistenceType.Value() == PERSISTENCE_TYPE_TEMPORARY) {
       if (op->mOriginOrPattern.IsPattern() &&
           !originCollection.ContainsPattern(op->mOriginOrPattern)) {
         originCollection.AddPattern(op->mOriginOrPattern);
       }
     }
   }
 
   for (index = 0; index < mSynchronizedOps.Length(); index++) {
     nsAutoPtr<SynchronizedOp>& op = mSynchronizedOps[index];
-    if (!op->mPersistenceType ||
+    if (op->mPersistenceType.IsNull() ||
         op->mPersistenceType.Value() == PERSISTENCE_TYPE_TEMPORARY) {
       if (op->mOriginOrPattern.IsOrigin() &&
           !originCollection.ContainsOrigin(op->mOriginOrPattern)) {
         originCollection.AddOrigin(op->mOriginOrPattern);
       }
     }
   }
 
--- a/dom/webidl/CanvasRenderingContext2D.webidl
+++ b/dom/webidl/CanvasRenderingContext2D.webidl
@@ -69,30 +69,30 @@ interface CanvasRenderingContext2D {
   void clearRect(double x, double y, double w, double h);
   [LenientFloat]
   void fillRect(double x, double y, double w, double h);
   [LenientFloat]
   void strokeRect(double x, double y, double w, double h);
 
   // path API (see also CanvasPathMethods)
   void beginPath();
-  void fill([TreatUndefinedAs=Missing] optional CanvasWindingRule winding = "nonzero");
+  void fill(optional CanvasWindingRule winding = "nonzero");
 // NOT IMPLEMENTED  void fill(Path path);
   void stroke();
 // NOT IMPLEMENTED  void stroke(Path path);
 // NOT IMPLEMENTED  void drawSystemFocusRing(Element element);
 // NOT IMPLEMENTED  void drawSystemFocusRing(Path path, Element element);
 // NOT IMPLEMENTED  boolean drawCustomFocusRing(Element element);
 // NOT IMPLEMENTED  boolean drawCustomFocusRing(Path path, Element element);
 // NOT IMPLEMENTED  void scrollPathIntoView();
 // NOT IMPLEMENTED  void scrollPathIntoView(Path path);
-  void clip([TreatUndefinedAs=Missing] optional CanvasWindingRule winding = "nonzero");
+  void clip(optional CanvasWindingRule winding = "nonzero");
 // NOT IMPLEMENTED  void clip(Path path);
 // NOT IMPLEMENTED  void resetClip();
-  boolean isPointInPath(unrestricted double x, unrestricted double y, [TreatUndefinedAs=Missing] optional CanvasWindingRule winding = "nonzero");
+  boolean isPointInPath(unrestricted double x, unrestricted double y, optional CanvasWindingRule winding = "nonzero");
 // NOT IMPLEMENTED  boolean isPointInPath(Path path, unrestricted double x, unrestricted double y);
   boolean isPointInStroke(double x, double y);
 
   // text (see also the CanvasDrawingStyles interface)
   [Throws, LenientFloat]
   void fillText(DOMString text, double x, double y, optional double maxWidth);
   [Throws, LenientFloat]
   void strokeText(DOMString text, double x, double y, optional double maxWidth);
--- a/dom/webidl/Notification.webidl
+++ b/dom/webidl/Notification.webidl
@@ -22,32 +22,32 @@ interface Notification : EventTarget {
   attribute EventHandler onclick;
 
   attribute EventHandler onshow;
 
   attribute EventHandler onerror;
 
   attribute EventHandler onclose;
 
-  [Constant]
+  [Pure]
   readonly attribute DOMString title;
 
-  [Constant]
+  [Pure]
   readonly attribute NotificationDirection dir;
 
-  [Constant]
+  [Pure]
   readonly attribute DOMString? lang;
 
-  [Constant]
+  [Pure]
   readonly attribute DOMString? body;
 
   [Constant]
   readonly attribute DOMString? tag;
 
-  [Constant]
+  [Pure]
   readonly attribute DOMString? icon;
 
   void close();
 };
 
 dictionary NotificationOptions {
   NotificationDirection dir = "auto";
   DOMString lang = "";
--- a/dom/webidl/Promise.webidl
+++ b/dom/webidl/Promise.webidl
@@ -23,14 +23,14 @@ interface Promise {
   // Promise object in this scope without having resolved the interface object
   // first.
   [Creator, Throws, Func="mozilla::dom::Promise::EnabledForScope"]
   static Promise resolve(any value); // same as any(value)
   [Creator, Throws, Func="mozilla::dom::Promise::EnabledForScope"]
   static Promise reject(any value);
 
   [Creator]
-  Promise then([TreatUndefinedAs=Missing] optional AnyCallback fulfillCallback,
-               [TreatUndefinedAs=Missing] optional AnyCallback rejectCallback);
+  Promise then(optional AnyCallback fulfillCallback,
+               optional AnyCallback rejectCallback);
 
   [Creator]
-  Promise catch([TreatUndefinedAs=Missing] optional AnyCallback rejectCallback);
+  Promise catch(optional AnyCallback rejectCallback);
 };
--- a/dom/webidl/XMLHttpRequest.webidl
+++ b/dom/webidl/XMLHttpRequest.webidl
@@ -66,17 +66,19 @@ interface XMLHttpRequest : XMLHttpReques
   const unsigned short HEADERS_RECEIVED = 2;
   const unsigned short LOADING = 3;
   const unsigned short DONE = 4;
 
   readonly attribute unsigned short readyState;
 
   // request
   [Throws]
-  void open(ByteString method, DOMString url, optional boolean async = true,
+  void open(ByteString method, DOMString url);
+  [Throws]
+  void open(ByteString method, DOMString url, boolean async,
             optional DOMString? user, optional DOMString? password);
   [Throws]
   void setRequestHeader(ByteString header, ByteString value);
 
   [SetterThrows]
   attribute unsigned long timeout;
 
   [SetterThrows]
--- a/dom/workers/XMLHttpRequest.h
+++ b/dom/workers/XMLHttpRequest.h
@@ -116,16 +116,21 @@ public:
 #undef IMPL_GETTER_AND_SETTER
 
   uint16_t
   ReadyState() const
   {
     return mStateData.mReadyState;
   }
 
+  void Open(const nsACString& aMethod, const nsAString& aUrl, ErrorResult& aRv)
+  {
+    Open(aMethod, aUrl, true, Optional<nsAString>(),
+         Optional<nsAString>(), aRv);
+  }
   void
   Open(const nsACString& aMethod, const nsAString& aUrl, bool aAsync,
        const Optional<nsAString>& aUser, const Optional<nsAString>& aPassword,
        ErrorResult& aRv);
 
   void
   SetRequestHeader(const nsACString& aHeader, const nsACString& aValue,
                    ErrorResult& aRv);
--- a/editor/libeditor/base/InsertElementTxn.cpp
+++ b/editor/libeditor/base/InsertElementTxn.cpp
@@ -57,18 +57,17 @@ NS_IMETHODIMP InsertElementTxn::Init(nsI
 
 NS_IMETHODIMP InsertElementTxn::DoTransaction(void)
 {
 #ifdef DEBUG
   if (gNoisy) 
   { 
     nsCOMPtr<nsIContent>nodeAsContent = do_QueryInterface(mNode);
     nsCOMPtr<nsIContent>parentAsContent = do_QueryInterface(mParent);
-    nsString namestr;
-    mNode->GetNodeName(namestr);
+    nsString namestr = mNode->NodeName();
     char* nodename = ToNewCString(namestr);
     printf("%p Do Insert Element of %p <%s> into parent %p at offset %d\n", 
            static_cast<void*>(this),
            static_cast<void*>(nodeAsContent.get()),
            nodename,
            static_cast<void*>(parentAsContent.get()),
            mOffset); 
     nsMemory::Free(nodename);
--- a/gfx/2d/PathCairo.cpp
+++ b/gfx/2d/PathCairo.cpp
@@ -264,31 +264,31 @@ PathCairo::SetPathOnContext(cairo_t *aCo
     cairo_append_path(aContext, &path);
   }
 }
 
 void
 PathCairo::AppendPathToBuilder(PathBuilderCairo *aBuilder, const Matrix *aTransform) const
 {
   if (aTransform) {
-    int i = 0;
+    size_t i = 0;
     while (i < mPathData.size()) {
       uint32_t pointCount = mPathData[i].header.length - 1;
       aBuilder->mPathData.push_back(mPathData[i]);
       i++;
-      for (int c = 0; c < pointCount; c++) {
+      for (uint32_t c = 0; c < pointCount; c++) {
         cairo_path_data_t data;
         Point newPoint = *aTransform * Point(mPathData[i].point.x, mPathData[i].point.y);
         data.point.x = newPoint.x;
         data.point.y = newPoint.y;
         aBuilder->mPathData.push_back(data);
         i++;
       }
     }
   } else {
-    for (int i = 0; i < mPathData.size(); i++) {
+    for (size_t i = 0; i < mPathData.size(); i++) {
       aBuilder->mPathData.push_back(mPathData[i]);
     }
   }
 }
 
 }
 }
--- a/js/public/MemoryMetrics.h
+++ b/js/public/MemoryMetrics.h
@@ -56,22 +56,22 @@ struct InefficientNonFlatteningStringHas
 //
 // In some classes, one or more of the macro arguments aren't used.  We use '_'
 // for those.
 //
 #define DECL_SIZE(gc, mSize)                      size_t mSize;
 #define ZERO_SIZE(gc, mSize)                      mSize(0),
 #define COPY_OTHER_SIZE(gc, mSize)                mSize(other.mSize),
 #define ADD_OTHER_SIZE(gc, mSize)                 mSize += other.mSize;
-#define ADD_SIZE_TO_N_IF_LIVE_GC_THING(gc, mSize) n += (gc == js::IsLiveGCThing) ? mSize : 0;
+#define ADD_SIZE_TO_N_IF_LIVE_GC_THING(gc, mSize) n += (gc) ? mSize : 0;
 
 // Used to annotate which size_t fields measure live GC things and which don't.
 enum {
-    IsLiveGCThing,
-    NotLiveGCThing
+    NotLiveGCThing = false,
+    IsLiveGCThing = true
 };
 
 struct ZoneStatsPod
 {
 #define FOR_EACH_SIZE(macro) \
     macro(NotLiveGCThing, gcHeapArenaAdmin) \
     macro(NotLiveGCThing, unusedGCThings) \
     macro(IsLiveGCThing,  lazyScriptsGCHeap) \
--- a/js/src/config/config.mk
+++ b/js/src/config/config.mk
@@ -347,17 +347,16 @@ DEFINES += \
 	  -DIMPL_LIBXUL \
 		$(NULL)
 
 ifndef JS_SHARED_LIBRARY
 DEFINES += -DSTATIC_EXPORTABLE_JS_API
 endif
 endif
 
-# Flags passed to JarMaker.py
 MAKE_JARS_FLAGS = \
 	-t $(topsrcdir) \
 	-f $(MOZ_CHROME_FILE_FORMAT) \
 	$(NULL)
 
 ifdef USE_EXTENSION_MANIFEST
 MAKE_JARS_FLAGS += -e
 endif
--- a/js/src/config/rules.mk
+++ b/js/src/config/rules.mk
@@ -1446,20 +1446,20 @@ endif
 ifneq (,$(DIST_SUBDIR))
 ifndef XPI_ROOT_APPID
 $(error XPI_ROOT_APPID is not defined - langpacks will break.)
 endif
 endif
 endif
 
 libs realchrome:: $(CHROME_DEPS) $(FINAL_TARGET)/chrome
-	$(PYTHON) $(MOZILLA_DIR)/config/JarMaker.py \
+	$(call py_action,jar_maker,\
 	  $(QUIET) -j $(FINAL_TARGET)/chrome \
 	  $(MAKE_JARS_FLAGS) $(XULPPFLAGS) $(DEFINES) $(ACDEFINES) \
-	  $(JAR_MANIFEST)
+	  $(JAR_MANIFEST))
 
 endif
 endif
 
 ifneq ($(DIST_FILES),)
 DIST_FILES_PATH := $(FINAL_TARGET)
 DIST_FILES_FLAGS := $(XULAPP_DEFINES)
 PP_TARGETS += DIST_FILES
--- a/js/src/frontend/BytecodeCompiler.cpp
+++ b/js/src/frontend/BytecodeCompiler.cpp
@@ -449,23 +449,28 @@ frontend::CompileLazyFunction(JSContext 
         return false;
 
     script->bindings = pn->pn_funbox->bindings;
 
     if (lazy->directlyInsideEval())
         script->directlyInsideEval = true;
     if (lazy->usesArgumentsAndApply())
         script->usesArgumentsAndApply = true;
+    if (lazy->hasBeenCloned())
+        script->hasBeenCloned = true;
 
     BytecodeEmitter bce(/* parent = */ nullptr, &parser, pn->pn_funbox, script, options.forEval,
                         /* evalCaller = */ NullPtr(), /* hasGlobalScope = */ true,
                         options.lineno, BytecodeEmitter::LazyFunction);
     if (!bce.init())
         return false;
 
+    if (lazy->treatAsRunOnce())
+        bce.lazyRunOnceLambda = true;
+
     return EmitFunctionScript(cx, &bce, pn->pn_body);
 }
 
 // Compile a JS function body, which might appear as the value of an event
 // handler attribute in an HTML <INPUT> tag, or in a Function() constructor.
 static bool
 CompileFunctionBody(JSContext *cx, MutableHandleFunction fun, CompileOptions options,
                     const AutoNameVector &formals, const jschar *chars, size_t length,
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -102,16 +102,17 @@ BytecodeEmitter::BytecodeEmitter(Bytecod
     tryNoteList(sc->context),
     arrayCompDepth(0),
     emitLevel(0),
     constList(sc->context),
     typesetCount(0),
     hasSingletons(false),
     emittingForInit(false),
     emittingRunOnceLambda(false),
+    lazyRunOnceLambda(false),
     insideEval(insideEval),
     hasGlobalScope(hasGlobalScope),
     emitterMode(emitterMode)
 {
     JS_ASSERT_IF(evalCaller, insideEval);
 }
 
 bool
@@ -2661,20 +2662,21 @@ frontend::EmitFunctionScript(ExclusiveCo
         bce->switchToMain();
     }
 
     /*
      * Emit a prologue for run-once scripts which will deoptimize JIT code if
      * the script ends up running multiple times via foo.caller related
      * shenanigans.
      */
-    bool runOnce = bce->parent &&
-        bce->parent->emittingRunOnceLambda &&
+    bool runOnce =
+        bce->isRunOnceLambda() &&
         !funbox->argumentsHasLocalBinding() &&
-        !funbox->isGenerator();
+        !funbox->isGenerator() &&
+        !funbox->function()->name();
     if (runOnce) {
         bce->switchToProlog();
         if (Emit1(cx, bce, JSOP_RUNONCE) < 0)
             return false;
         bce->switchToMain();
     }
 
     if (!EmitTree(cx, bce, body))
@@ -4783,29 +4785,29 @@ EmitFunc(ExclusiveContext *cx, BytecodeE
      * make a deep clone of its contents.
      */
     if (fun->isInterpreted()) {
         bool singleton =
             cx->typeInferenceEnabled() &&
             bce->script->compileAndGo &&
             fun->isInterpreted() &&
             (bce->checkSingletonContext() ||
-             (!bce->isInLoop() &&
-              bce->parent &&
-              bce->parent->emittingRunOnceLambda));
+             (!bce->isInLoop() && bce->isRunOnceLambda()));
         if (!JSFunction::setTypeForScriptedFunction(cx, fun, singleton))
             return false;
 
         if (fun->isInterpretedLazy()) {
             if (!fun->lazyScript()->sourceObject()) {
                 JSObject *scope = bce->blockChain;
                 if (!scope && bce->sc->isFunctionBox())
                     scope = bce->sc->asFunctionBox()->function();
                 fun->lazyScript()->setParent(scope, bce->script->sourceObject());
             }
+            if (bce->emittingRunOnceLambda)
+                fun->lazyScript()->setTreatAsRunOnce();
         } else {
             SharedContext *outersc = bce->sc;
 
             if (outersc->isFunctionBox() && outersc->asFunctionBox()->mightAliasLocals())
                 funbox->setMightAliasLocals();      // inherit mightAliasLocals from parent
             JS_ASSERT_IF(outersc->strict, funbox->strict);
 
             // Inherit most things (principals, version, etc) from the parent.
--- a/js/src/frontend/BytecodeEmitter.h
+++ b/js/src/frontend/BytecodeEmitter.h
@@ -119,16 +119,22 @@ struct BytecodeEmitter
     uint16_t        typesetCount;   /* Number of JOF_TYPESET opcodes generated */
 
     bool            hasSingletons:1;    /* script contains singleton initializer JSOP_OBJECT */
 
     bool            emittingForInit:1;  /* true while emitting init expr of for; exclude 'in' */
 
     bool            emittingRunOnceLambda:1; /* true while emitting a lambda which is only
                                                 expected to run once. */
+    bool            lazyRunOnceLambda:1; /* true while lazily emitting a script for
+                                          * a lambda which is only expected to run once. */
+
+    bool isRunOnceLambda() {
+        return (parent && parent->emittingRunOnceLambda) || lazyRunOnceLambda;
+    }
 
     bool            insideEval:1;       /* True if compiling an eval-expression or a function
                                            nested inside an eval. */
 
     const bool      hasGlobalScope:1;   /* frontend::CompileScript's scope chain is the
                                            global object */
 
     enum EmitterMode {
--- a/js/src/gc/StoreBuffer.cpp
+++ b/js/src/gc/StoreBuffer.cpp
@@ -117,35 +117,16 @@ StoreBuffer::MonoTypeBuffer<T>::mark(JST
         T *edge = e.get<T>();
         if (edge->isNullEdge())
             continue;
         edge->mark(trc);
 
     }
 }
 
-namespace js {
-namespace gc {
-class AccumulateEdgesTracer : public JSTracer
-{
-    EdgeSet *edges;
-
-    static void tracer(JSTracer *jstrc, void **thingp, JSGCTraceKind kind) {
-        AccumulateEdgesTracer *trc = static_cast<AccumulateEdgesTracer *>(jstrc);
-        trc->edges->put(thingp);
-    }
-
-  public:
-    AccumulateEdgesTracer(JSRuntime *rt, EdgeSet *edgesArg) : edges(edgesArg) {
-        JS_TracerInit(this, rt, AccumulateEdgesTracer::tracer);
-    }
-};
-} /* namespace gc */
-} /* namespace js */
-
 /*** RelocatableMonoTypeBuffer ***/
 
 template <typename T>
 void
 StoreBuffer::RelocatableMonoTypeBuffer<T>::compactMoved()
 {
     LifoAlloc &storage = this->storage_;
     EdgeSet &invalidated = this->owner->edgeSet;
--- a/js/src/gc/StoreBuffer.h
+++ b/js/src/gc/StoreBuffer.h
@@ -20,18 +20,16 @@
 
 #include "ds/LifoAlloc.h"
 #include "gc/Nursery.h"
 #include "js/Tracer.h"
 
 namespace js {
 namespace gc {
 
-class AccumulateEdgesTracer;
-
 /*
  * BufferableRef represents an abstract reference for use in the generational
  * GC's remembered set. Entries in the store buffer that cannot be represented
  * with the simple pointer-to-a-pointer scheme must derive from this class and
  * use the generic store buffer interface.
  */
 class BufferableRef
 {
--- a/js/src/jit/IonCaches.cpp
+++ b/js/src/jit/IonCaches.cpp
@@ -2726,18 +2726,20 @@ CanAttachNativeSetProp(HandleObject obj,
         return SetPropertyIC::CanAttachSetSlot;
 
     // If we couldn't find the property on the object itself, do a full, but
     // still pure lookup for setters.
     if (!LookupPropertyPure(obj, id, holder.address(), shape.address()))
         return SetPropertyIC::CanAttachNone;
 
     // If the object doesn't have the property, we don't know if we can attach
-    // a stub to add the property until we do the VM call to add.
-    if (!shape)
+    // a stub to add the property until we do the VM call to add. If the
+    // property exists as a data property on the prototype, we should add
+    // a new, shadowing property.
+    if (!shape || (obj != holder && shape->hasDefaultSetter() && shape->hasSlot()))
         return SetPropertyIC::MaybeCanAttachAddSlot;
 
     if (IsCacheableSetPropCallPropertyOp(obj, holder, shape) ||
         IsCacheableSetPropCallNative(obj, holder, shape))
     {
         return SetPropertyIC::CanAttachCallSetter;
     }
 
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -2937,16 +2937,17 @@ LazyScript::LazyScript(JSFunction *fun, 
     numInnerFunctions_(numInnerFunctions),
     generatorKindBits_(GeneratorKindAsBits(NotGenerator)),
     strict_(false),
     bindingsAccessedDynamically_(false),
     hasDebuggerStatement_(false),
     directlyInsideEval_(false),
     usesArgumentsAndApply_(false),
     hasBeenCloned_(false),
+    treatAsRunOnce_(false),
     begin_(begin),
     end_(end),
     lineno_(lineno),
     column_(column)
 {
     JS_ASSERT(this->version() == version);
     JS_ASSERT(begin <= end);
 }
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -1178,27 +1178,28 @@ class LazyScript : public gc::BarrieredC
 #if JS_BITS_PER_WORD == 32
     uint32_t padding;
 #endif
 
     // Assorted bits that should really be in ScriptSourceObject.
     uint32_t version_ : 8;
 
     uint32_t numFreeVariables_ : 24;
-    uint32_t numInnerFunctions_ : 24;
+    uint32_t numInnerFunctions_ : 23;
 
     uint32_t generatorKindBits_:2;
 
     // N.B. These are booleans but need to be uint32_t to pack correctly on MSVC.
     uint32_t strict_ : 1;
     uint32_t bindingsAccessedDynamically_ : 1;
     uint32_t hasDebuggerStatement_ : 1;
     uint32_t directlyInsideEval_:1;
     uint32_t usesArgumentsAndApply_:1;
     uint32_t hasBeenCloned_:1;
+    uint32_t treatAsRunOnce_:1;
 
     // Source location for the script.
     uint32_t begin_;
     uint32_t end_;
     uint32_t lineno_;
     uint32_t column_;
 
     LazyScript(JSFunction *fun, void *table,
@@ -1305,16 +1306,23 @@ class LazyScript : public gc::BarrieredC
 
     bool hasBeenCloned() const {
         return hasBeenCloned_;
     }
     void setHasBeenCloned() {
         hasBeenCloned_ = true;
     }
 
+    bool treatAsRunOnce() const {
+        return treatAsRunOnce_;
+    }
+    void setTreatAsRunOnce() {
+        treatAsRunOnce_ = true;
+    }
+
     ScriptSource *source() const {
         return sourceObject()->source();
     }
     uint32_t begin() const {
         return begin_;
     }
     uint32_t end() const {
         return end_;
--- a/js/xpconnect/tests/unit/test_allowedDomainsXHR.js
+++ b/js/xpconnect/tests/unit/test_allowedDomainsXHR.js
@@ -47,17 +47,17 @@ function run_test()
   httpserver.start(4444);
 
   httpserver2.registerPathHandler(negativetestpath, serverHandler);
   httpserver2.start(4445);
 
   // Test sync XHR sending
   cu.evalInSandbox('var createXHR = ' + createXHR.toString(), sb);
   var res = cu.evalInSandbox('var sync = createXHR("4444/simple"); sync.send(null); sync', sb);
-  checkResults(res);
+  do_check_true(checkResults(res));
 
   // negative test sync XHR sending (to ensure that the xhr do not have chrome caps, see bug 779821)
   try {
     cu.evalInSandbox('var createXHR = ' + createXHR.toString(), sb);
     var res = cu.evalInSandbox('var sync = createXHR("4445/negative"); sync.send(null); sync', sb);
     do_check_false(true, "XHR created from sandbox should not have chrome caps");
   } catch (e) {
     do_check_true(true);
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -72,16 +72,32 @@ NS_NewHTMLScrollFrame(nsIPresShell* aPre
 NS_IMPL_FRAMEARENA_HELPERS(nsHTMLScrollFrame)
 
 nsHTMLScrollFrame::nsHTMLScrollFrame(nsIPresShell* aShell, nsStyleContext* aContext, bool aIsRoot)
   : nsContainerFrame(aContext),
     mInner(ALLOW_THIS_IN_INITIALIZER_LIST(this), aIsRoot)
 {
 }
 
+void
+nsHTMLScrollFrame::ScrollbarActivityStarted() const
+{
+  if (mInner.mScrollbarActivity) {
+    mInner.mScrollbarActivity->ActivityStarted();
+  }
+}
+
+void
+nsHTMLScrollFrame::ScrollbarActivityStopped() const
+{
+  if (mInner.mScrollbarActivity) {
+    mInner.mScrollbarActivity->ActivityStopped();
+  }
+}
+
 nsresult
 nsHTMLScrollFrame::CreateAnonymousContent(nsTArray<ContentInfo>& aElements)
 {
   return mInner.CreateAnonymousContent(aElements);
 }
 
 void
 nsHTMLScrollFrame::AppendAnonymousContentTo(nsBaseContentList& aElements,
@@ -897,16 +913,32 @@ nsXULScrollFrame::nsXULScrollFrame(nsIPr
                                    bool aIsRoot, bool aClipAllDescendants)
   : nsBoxFrame(aShell, aContext, aIsRoot),
     mInner(ALLOW_THIS_IN_INITIALIZER_LIST(this), aIsRoot)
 {
   SetLayoutManager(nullptr);
   mInner.mClipAllDescendants = aClipAllDescendants;
 }
 
+void
+nsXULScrollFrame::ScrollbarActivityStarted() const
+{
+  if (mInner.mScrollbarActivity) {
+    mInner.mScrollbarActivity->ActivityStarted();
+  }
+}
+
+void
+nsXULScrollFrame::ScrollbarActivityStopped() const
+{
+  if (mInner.mScrollbarActivity) {
+    mInner.mScrollbarActivity->ActivityStopped();
+  }
+}
+
 nsMargin
 nsGfxScrollFrameInner::GetDesiredScrollbarSizes(nsBoxLayoutState* aState)
 {
   NS_ASSERTION(aState && aState->GetRenderingContext(),
                "Must have rendering context in layout state for size "
                "computations");
 
   nsMargin result(0, 0, 0, 0);
--- a/layout/generic/nsGfxScrollFrame.h
+++ b/layout/generic/nsGfxScrollFrame.h
@@ -515,16 +515,19 @@ public:
   virtual void AppendAnonymousContentTo(nsBaseContentList& aElements,
                                         uint32_t aFilter) MOZ_OVERRIDE;
 
   // nsIScrollbarOwner
   virtual nsIFrame* GetScrollbarBox(bool aVertical) MOZ_OVERRIDE {
     return mInner.GetScrollbarBox(aVertical);
   }
 
+  virtual void ScrollbarActivityStarted() const MOZ_OVERRIDE;
+  virtual void ScrollbarActivityStopped() const MOZ_OVERRIDE;
+
   // nsIScrollableFrame
   virtual nsIFrame* GetScrolledFrame() const MOZ_OVERRIDE {
     return mInner.GetScrolledFrame();
   }
   virtual mozilla::ScrollbarStyles GetScrollbarStyles() const {
     return mInner.GetScrollbarStylesFromFrame();
   }
   virtual uint32_t GetScrollbarVisibility() const MOZ_OVERRIDE {
@@ -805,16 +808,19 @@ public:
   static void AdjustReflowStateForPrintPreview(nsBoxLayoutState& aState, bool& aSetBack);
   static void AdjustReflowStateBack(nsBoxLayoutState& aState, bool aSetBack);
 
   // nsIScrollbarOwner
   virtual nsIFrame* GetScrollbarBox(bool aVertical) MOZ_OVERRIDE {
     return mInner.GetScrollbarBox(aVertical);
   }
 
+  virtual void ScrollbarActivityStarted() const MOZ_OVERRIDE;
+  virtual void ScrollbarActivityStopped() const MOZ_OVERRIDE;
+
   // nsIScrollableFrame
   virtual nsIFrame* GetScrolledFrame() const MOZ_OVERRIDE {
     return mInner.GetScrolledFrame();
   }
   virtual mozilla::ScrollbarStyles GetScrollbarStyles() const {
     return mInner.GetScrollbarStylesFromFrame();
   }
   virtual uint32_t GetScrollbarVisibility() const MOZ_OVERRIDE {
--- a/layout/generic/nsIScrollbarOwner.h
+++ b/layout/generic/nsIScrollbarOwner.h
@@ -18,11 +18,18 @@ class nsIScrollbarOwner : public nsQuery
 public:
   NS_DECL_QUERYFRAME_TARGET(nsIScrollbarOwner)
 
   /**
    * Obtain the frame for the horizontal or vertical scrollbar, or null
    * if there is no such box.
    */
   virtual nsIFrame* GetScrollbarBox(bool aVertical) = 0;
+
+  /**
+   * Show or hide scrollbars on 2 fingers touch.
+   * Subclasses should call their ScrollbarActivity's corresponding methods.
+   */
+  virtual void ScrollbarActivityStarted() const = 0;
+  virtual void ScrollbarActivityStopped() const = 0;
 };
 
 #endif
--- a/layout/media/moz.build
+++ b/layout/media/moz.build
@@ -3,9 +3,10 @@
 # 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/.
 
 MODULE = 'layout'
 
 LIBRARY_NAME = 'gkmedias'
 
-DIRS += ['webrtc']
+if CONFIG['MOZ_WEBRTC']:
+    DIRS += ['webrtc']
--- a/layout/xul/tree/nsTreeBodyFrame.cpp
+++ b/layout/xul/tree/nsTreeBodyFrame.cpp
@@ -4491,16 +4491,32 @@ nsTreeBodyFrame::PostScrollEvent()
   if (NS_FAILED(NS_DispatchToCurrentThread(ev))) {
     NS_WARNING("failed to dispatch ScrollEvent");
   } else {
     mScrollEvent = ev;
   }
 }
 
 void
+nsTreeBodyFrame::ScrollbarActivityStarted() const
+{
+  if (mScrollbarActivity) {
+    mScrollbarActivity->ActivityStarted();
+  }
+}
+
+void
+nsTreeBodyFrame::ScrollbarActivityStopped() const
+{
+  if (mScrollbarActivity) {
+    mScrollbarActivity->ActivityStopped();
+  }
+}
+
+void
 nsTreeBodyFrame::DetachImageListeners()
 {
   mCreatedListeners.Clear();
 }
 
 void
 nsTreeBodyFrame::RemoveTreeImageListener(nsTreeImageListener* aListener)
 {
--- a/layout/xul/tree/nsTreeBodyFrame.h
+++ b/layout/xul/tree/nsTreeBodyFrame.h
@@ -460,16 +460,19 @@ protected:
     void Revoke() { mInner = nullptr; }
   private:
     nsTreeBodyFrame* mInner;
   };
 
   void PostScrollEvent();
   void FireScrollEvent();
 
+  virtual void ScrollbarActivityStarted() const MOZ_OVERRIDE;
+  virtual void ScrollbarActivityStopped() const MOZ_OVERRIDE;
+
   /**
    * Clear the pointer to this frame for all nsTreeImageListeners that were
    * created by this frame.
    */
   void DetachImageListeners();
 
 #ifdef ACCESSIBILITY
   /**
--- a/mach
+++ b/mach
@@ -15,36 +15,41 @@ def ancestors(path):
         if child == "":
             break
 
 def load_mach(topsrcdir):
     sys.path[0:0] = [os.path.join(topsrcdir, "build")]
     import mach_bootstrap
     return mach_bootstrap.bootstrap(topsrcdir)
 
-# Check whether the current directory is within a mach src or obj dir.
-for dir_path in ancestors(os.getcwd()):
-    # If we find a "mozinfo.json" file, we are in the objdir.
-    mozinfo_path = os.path.join(dir_path, "mozinfo.json")
-    if os.path.isfile(mozinfo_path):
-        import json
-        info = json.load(open(mozinfo_path))
-        if "mozconfig" in info and "MOZCONFIG" not in os.environ:
-            # If the MOZCONFIG environment variable is not already set, set it
-            # to the value from mozinfo.json.  This will tell the build system
-            # to look for a config file at the path in $MOZCONFIG rather than
-            # its default locations.
-            #
-            # Note: subprocess requires native strings in os.environ on Windows
-            os.environ[b"MOZCONFIG"] = str(info["mozconfig"])
+def main(args):
+    # Check whether the current directory is within a mach src or obj dir.
+    for dir_path in ancestors(os.getcwd()):
+        # If we find a "mozinfo.json" file, we are in the objdir.
+        mozinfo_path = os.path.join(dir_path, 'mozinfo.json')
+        if os.path.isfile(mozinfo_path):
+            import json
+            info = json.load(open(mozinfo_path))
+            if 'mozconfig' in info and 'MOZCONFIG' not in os.environ:
+                # If the MOZCONFIG environment variable is not already set, set it
+                # to the value from mozinfo.json.  This will tell the build system
+                # to look for a config file at the path in $MOZCONFIG rather than
+                # its default locations.
+                #
+                # Note: subprocess requires native strings in os.environ on Windows
+                os.environ[b'MOZCONFIG'] = str(info['mozconfig'])
 
-        if "topsrcdir" in info:
-            # Continue searching for mach_bootstrap in the source directory.
-            dir_path = info["topsrcdir"]
+            if 'topsrcdir' in info:
+                # Continue searching for mach_bootstrap in the source directory.
+                dir_path = info['topsrcdir']
 
-    # If we find the mach bootstrap module, we are in the srcdir.
-    mach_path = os.path.join(dir_path, "build/mach_bootstrap.py")
-    if os.path.isfile(mach_path):
-        mach = load_mach(dir_path)
-        sys.exit(mach.run(sys.argv[1:]))
+        # If we find the mach bootstrap module, we are in the srcdir.
+        mach_path = os.path.join(dir_path, 'build/mach_bootstrap.py')
+        if os.path.isfile(mach_path):
+            mach = load_mach(dir_path)
+            sys.exit(mach.run(args[1:]))
 
-print("Could not run mach: No mach source directory found")
-sys.exit(1)
+    print('Could not run mach: No mach source directory found.')
+    sys.exit(1)
+
+
+if __name__ == '__main__':
+    main(sys.argv)
--- a/mobile/locales/Makefile.in
+++ b/mobile/locales/Makefile.in
@@ -15,22 +15,16 @@
 include $(topsrcdir)/config/config.mk
 
 USE_AUTOTARGETS_MK=1
 include $(topsrcdir)/config/makefiles/makeutils.mk
 
 # Separate items of contention
 tgt-gendir = .deps/generated_$(AB_CD)
 
-jar-maker = \
-  $(firstword \
-    $(wildcard $(MOZILLA_DIR)/config/JarMaker.py) \
-    $(topsrcdir)/config/JarMaker.py \
-  )
-
 GENERATED_DIRS += .deps
 
 ifdef LOCALE_MERGEDIR
 vpath book%.inc $(LOCALE_MERGEDIR)/mobile/profile
 endif
 vpath book%.inc $(LOCALE_SRCDIR)/profile
 ifdef LOCALE_MERGEDIR
 vpath book%.inc @srcdir@/en-US/profile
@@ -125,28 +119,27 @@ search-dir-deps = \
   $(dir-chrome) \
   $(NULL)
 
 search-preqs =\
   $(call mkdir_deps,$(dir $(search-jar-ts))) \
   $(call mkdir_deps,$(FINAL_TARGET)/chrome) \
   $(search-jar) \
   $(search-dir-deps) \
-  $(jar-maker) \
   $(if $(IS_LANGUAGE_REPACK),FORCE) \
   $(GLOBAL_DEPS) \
   $(NULL)
 
 .PHONY: searchplugins
 searchplugins: $(search-preqs)
-	$(PYTHON) $(jar-maker) \
+	$(call py_action,jar_maker,\
           $(QUIET) -j $(FINAL_TARGET)/chrome \
           -s $(topsrcdir)/$(relativesrcdir)/en-US/searchplugins \
           -s $(LOCALE_SRCDIR)/searchplugins \
-          $(MAKE_JARS_FLAGS) $(search-jar)
+          $(MAKE_JARS_FLAGS) $(search-jar))
 	$(TOUCH) $@
 
 include $(topsrcdir)/config/rules.mk
 
 
 #############
 libs-preqs =\
   $(call mkdir-deps,$(DIST)/install) \
--- a/python/mach/mach/base.py
+++ b/python/mach/mach/base.py
@@ -2,19 +2,18 @@
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 from __future__ import unicode_literals
 
 
 class CommandContext(object):
     """Holds run-time state so it can easily be passed to command providers."""
-    def __init__(self, topdir=None, cwd=None, settings=None, log_manager=None,
+    def __init__(self, cwd=None, settings=None, log_manager=None,
         commands=None):
-        self.topdir = topdir
         self.cwd = cwd
         self.settings = settings
         self.log_manager = log_manager
         self.commands = commands
 
 
 class MachError(Exception):
     """Base class for all errors raised by mach itself."""
--- a/python/mach/mach/dispatcher.py
+++ b/python/mach/mach/dispatcher.py
@@ -140,16 +140,17 @@ class CommandAction(argparse.Action):
             raise UnrecognizedArgumentError(command, extra)
 
     def _handle_main_help(self, parser):
         # Since we don't need full sub-parser support for the main help output,
         # we create groups in the ArgumentParser and populate each group with
         # arguments corresponding to command names. This has the side-effect
         # that argparse renders it nicely.
         r = self._mach_registrar
+        disabled_commands = []
 
         cats = [(k, v[2]) for k, v in r.categories.items()]
         sorted_cats = sorted(cats, key=itemgetter(1), reverse=True)
         for category, priority in sorted_cats:
             group = None
 
             for command in sorted(r.commands_by_category[category]):
                 handler = r.command_handlers[command]
@@ -164,26 +165,36 @@ class CommandAction(argparse.Action):
                         instance = handler.cls()
 
                     is_filtered = False
                     for c in handler.conditions:
                         if not c(instance):
                             is_filtered = True
                             break
                     if is_filtered:
+                        description = handler.description
+                        disabled_command = {'command': command, 'description': description}
+                        disabled_commands.append(disabled_command)
                         continue
 
                 if group is None:
                     title, description, _priority = r.categories[category]
                     group = parser.add_argument_group(title, description)
 
                 description = handler.description
                 group.add_argument(command, help=description,
                     action='store_true')
 
+        if disabled_commands:
+            title, description, _priority = r.categories['disabled']
+            group = parser.add_argument_group(title, description)
+            for c in disabled_commands:
+                group.add_argument(c['command'], help=c['description'],
+                    action='store_true')
+
         parser.print_help()
 
     def _handle_subcommand_help(self, parser, command):
         handler = self._mach_registrar.command_handlers.get(command)
 
         if not handler:
             raise UnknownCommandError(command, 'query')
 
--- a/python/mach/mach/main.py
+++ b/python/mach/mach/main.py
@@ -284,17 +284,17 @@ To see more help for a specific command,
             return 1
 
         finally:
             sys.stdin = orig_stdin
             sys.stdout = orig_stdout
             sys.stderr = orig_stderr
 
     def _run(self, argv):
-        context = CommandContext(topdir=self.cwd, cwd=self.cwd,
+        context = CommandContext(cwd=self.cwd,
             settings=self.settings, log_manager=self.log_manager,
             commands=Registrar)
 
         if self.populate_context_handler:
             self.populate_context_handler(context)
 
         parser = self.get_argument_parser(context)
 
new file mode 100644
--- /dev/null
+++ b/python/mozbuild/mozbuild/action/jar_maker.py
@@ -0,0 +1,15 @@
+# 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/.
+
+import sys
+
+import mozbuild.jar
+
+
+def main(args):
+    return mozbuild.jar.main(args)
+
+
+if __name__ == '__main__':
+    sys.exit(main(sys.argv[1:]))
--- a/python/mozbuild/mozbuild/base.py
+++ b/python/mozbuild/mozbuild/base.py
@@ -167,21 +167,23 @@ class MozbuildObject(ProcessExecutionMix
         config_topobjdir = MozbuildObject.resolve_mozconfig_topobjdir(
             topsrcdir, config)
 
         # If we're inside a objdir and the found mozconfig resolves to
         # another objdir, we abort. The reasoning here is that if you are
         # inside an objdir you probably want to perform actions on that objdir,
         # not another one. This prevents accidental usage of the wrong objdir
         # when the current objdir is ambiguous.
-        if topobjdir and config_topobjdir \
-            and not samepath(topobjdir, config_topobjdir) \
-            and not samepath(topobjdir, os.path.join(config_topobjdir, "mozilla")):
+        if topobjdir and config_topobjdir:
+            mozilla_dir = os.path.join(config_topobjdir, 'mozilla')
+            if not samepath(topobjdir, config_topobjdir) \
+                and (os.path.exists(mozilla_dir) and not samepath(topobjdir,
+                mozilla_dir)):
 
-            raise ObjdirMismatchException(topobjdir, config_topobjdir)
+                raise ObjdirMismatchException(topobjdir, config_topobjdir)
 
         topobjdir = topobjdir or config_topobjdir
         if topobjdir:
             topobjdir = os.path.normpath(topobjdir)
 
         # If we can't resolve topobjdir, oh well. The constructor will figure
         # it out via config.guess.
         return cls(topsrcdir, None, None, topobjdir=topobjdir)
rename from config/JarMaker.py
rename to python/mozbuild/mozbuild/jar.py
--- a/config/JarMaker.py
+++ b/python/mozbuild/mozbuild/jar.py
@@ -2,488 +2,536 @@
 # 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/.
 
 '''jarmaker.py provides a python class to package up chrome content by
 processing jar.mn files.
 
 See the documentation for jar.mn on MDC for further details on the format.
 '''
+
 import sys
 import os
-import os.path
 import errno
 import re
 import logging
 from time import localtime
 from MozZipFile import ZipFile
 from cStringIO import StringIO
 
 from mozbuild.util import (
     lock_file,
     PushbackIter,
 )
 
 from Preprocessor import Preprocessor
 from mozbuild.action.buildlist import addEntriesToListFile
-if sys.platform == "win32":
-  from ctypes import windll, WinError
-  CreateHardLink = windll.kernel32.CreateHardLinkA
+if sys.platform == 'win32':
+    from ctypes import windll, WinError
+    CreateHardLink = windll.kernel32.CreateHardLinkA
 
 __all__ = ['JarMaker']
 
-class ZipEntry:
-  '''Helper class for jar output.
+
+class ZipEntry(object):
+    '''Helper class for jar output.
+
+      This class defines a simple file-like object for a zipfile.ZipEntry
+      so that we can consecutively write to it and then close it.
+      This methods hooks into ZipFile.writestr on close().
+      '''
 
-  This class defines a simple file-like object for a zipfile.ZipEntry
-  so that we can consecutively write to it and then close it.
-  This methods hooks into ZipFile.writestr on close().
-  '''
-  def __init__(self, name, zipfile):
-    self._zipfile = zipfile
-    self._name = name
-    self._inner = StringIO()
+    def __init__(self, name, zipfile):
+        self._zipfile = zipfile
+        self._name = name
+        self._inner = StringIO()
+
+    def write(self, content):
+        '''Append the given content to this zip entry'''
 
-  def write(self, content):
-    'Append the given content to this zip entry'
-    self._inner.write(content)
-    return
+        self._inner.write(content)
+        return
 
-  def close(self):
-    'The close method writes the content back to the zip file.'
-    self._zipfile.writestr(self._name, self._inner.getvalue())
+    def close(self):
+        '''The close method writes the content back to the zip file.'''
+
+        self._zipfile.writestr(self._name, self._inner.getvalue())
+
 
 def getModTime(aPath):
-  if not os.path.isfile(aPath):
-    return 0
-  mtime = os.stat(aPath).st_mtime
-  return localtime(mtime)
+    if not os.path.isfile(aPath):
+        return 0
+    mtime = os.stat(aPath).st_mtime
+    return localtime(mtime)
 
 
 class JarMaker(object):
-  '''JarMaker reads jar.mn files and process those into jar files or
-  flat directories, along with chrome.manifest files.
-  '''
+    '''JarMaker reads jar.mn files and process those into jar files or
+      flat directories, along with chrome.manifest files.
+      '''
 
-  ignore = re.compile('\s*(\#.*)?$')
-  jarline = re.compile('(?:(?P<jarfile>[\w\d.\-\_\\\/]+).jar\:)|(?:\s*(\#.*)?)\s*$')
-  relsrcline = re.compile('relativesrcdir\s+(?P<relativesrcdir>.+?):')
-  regline = re.compile('\%\s+(.*)$')
-  entryre = '(?P<optPreprocess>\*)?(?P<optOverwrite>\+?)\s+'
-  entryline = re.compile(entryre + '(?P<output>[\w\d.\-\_\\\/\+\@]+)\s*(\((?P<locale>\%?)(?P<source>[\w\d.\-\_\\\/\@]+)\))?\s*$')
+    ignore = re.compile('\s*(\#.*)?$')
+    jarline = re.compile('(?:(?P<jarfile>[\w\d.\-\_\\\/]+).jar\:)|(?:\s*(\#.*)?)\s*$')
+    relsrcline = re.compile('relativesrcdir\s+(?P<relativesrcdir>.+?):')
+    regline = re.compile('\%\s+(.*)$')
+    entryre = '(?P<optPreprocess>\*)?(?P<optOverwrite>\+?)\s+'
+    entryline = re.compile(entryre
+                           + '(?P<output>[\w\d.\-\_\\\/\+\@]+)\s*(\((?P<locale>\%?)(?P<source>[\w\d.\-\_\\\/\@]+)\))?\s*$'
+                           )
+
+    def __init__(self, outputFormat='flat', useJarfileManifest=True,
+        useChromeManifest=False):
 
-  def __init__(self, outputFormat = 'flat', useJarfileManifest = True,
-               useChromeManifest = False):
-    self.outputFormat = outputFormat
-    self.useJarfileManifest = useJarfileManifest
-    self.useChromeManifest = useChromeManifest
-    self.pp = Preprocessor()
-    self.topsourcedir = None
-    self.sourcedirs = []
-    self.localedirs = None
-    self.l10nbase = None
-    self.l10nmerge = None
-    self.relativesrcdir = None
-    self.rootManifestAppId = None
+        self.outputFormat = outputFormat
+        self.useJarfileManifest = useJarfileManifest
+        self.useChromeManifest = useChromeManifest
+        self.pp = Preprocessor()
+        self.topsourcedir = None
+        self.sourcedirs = []
+        self.localedirs = None
+        self.l10nbase = None
+        self.l10nmerge = None
+        self.relativesrcdir = None
+        self.rootManifestAppId = None
 
-  def getCommandLineParser(self):
-    '''Get a optparse.OptionParser for jarmaker.
+    def getCommandLineParser(self):
+        '''Get a optparse.OptionParser for jarmaker.
+
+        This OptionParser has the options for jarmaker as well as
+        the options for the inner PreProcessor.
+        '''
+
+        # HACK, we need to unescape the string variables we get,
+        # the perl versions didn't grok strings right
 
-    This OptionParser has the options for jarmaker as well as
-    the options for the inner PreProcessor.
-    '''
-    # HACK, we need to unescape the string variables we get,
-    # the perl versions didn't grok strings right
-    p = self.pp.getCommandLineParser(unescapeDefines = True)
-    p.add_option('-f', type="choice", default="jar",
-                 choices=('jar', 'flat', 'symlink'),
-                 help="fileformat used for output", metavar="[jar, flat, symlink]")
-    p.add_option('-v', action="store_true", dest="verbose",
-                 help="verbose output")
-    p.add_option('-q', action="store_false", dest="verbose",
-                 help="verbose output")
-    p.add_option('-e', action="store_true",
-                 help="create chrome.manifest instead of jarfile.manifest")
-    p.add_option('--both-manifests', action="store_true",
-                 dest="bothManifests",
-                 help="create chrome.manifest and jarfile.manifest")
-    p.add_option('-s', type="string", action="append", default=[],
-                 help="source directory")
-    p.add_option('-t', type="string",
-                 help="top source directory")
-    p.add_option('-c', '--l10n-src', type="string", action="append",
-                 help="localization directory")
-    p.add_option('--l10n-base', type="string", action="store",
-                 help="base directory to be used for localization (requires relativesrcdir)")
-    p.add_option('--locale-mergedir', type="string", action="store",
-                 help="base directory to be used for l10n-merge (requires l10n-base and relativesrcdir)")
-    p.add_option('--relativesrcdir', type="string",
-                 help="relativesrcdir to be used for localization")
-    p.add_option('-j', type="string",
-                 help="jarfile directory")
-    p.add_option('--root-manifest-entry-appid', type="string",
-                 help="add an app id specific root chrome manifest entry.")
-    return p
+        p = self.pp.getCommandLineParser(unescapeDefines=True)
+        p.add_option('-f', type='choice', default='jar',
+            choices=('jar', 'flat', 'symlink'),
+            help='fileformat used for output',
+            metavar='[jar, flat, symlink]',
+            )
+        p.add_option('-v', action='store_true', dest='verbose',
+                     help='verbose output')
+        p.add_option('-q', action='store_false', dest='verbose',
+                     help='verbose output')
+        p.add_option('-e', action='store_true',
+                     help='create chrome.manifest instead of jarfile.manifest'
+                     )
+        p.add_option('--both-manifests', action='store_true',
+                     dest='bothManifests',
+                     help='create chrome.manifest and jarfile.manifest')
+        p.add_option('-s', type='string', action='append', default=[],
+                     help='source directory')
+        p.add_option('-t', type='string', help='top source directory')
+        p.add_option('-c', '--l10n-src', type='string', action='append'
+                     , help='localization directory')
+        p.add_option('--l10n-base', type='string', action='store',
+                     help='base directory to be used for localization (requires relativesrcdir)'
+                     )
+        p.add_option('--locale-mergedir', type='string', action='store'
+                     ,
+                     help='base directory to be used for l10n-merge (requires l10n-base and relativesrcdir)'
+                     )
+        p.add_option('--relativesrcdir', type='string',
+                     help='relativesrcdir to be used for localization')
+        p.add_option('-j', type='string', help='jarfile directory')
+        p.add_option('--root-manifest-entry-appid', type='string',
+                     help='add an app id specific root chrome manifest entry.'
+                     )
+        return p
 
-  def processIncludes(self, includes):
-    '''Process given includes with the inner PreProcessor.
+    def processIncludes(self, includes):
+        '''Process given includes with the inner PreProcessor.
+
+        Only use this for #defines, the includes shouldn't generate
+        content.
+        '''
+
+        self.pp.out = StringIO()
+        for inc in includes:
+            self.pp.do_include(inc)
+        includesvalue = self.pp.out.getvalue()
+        if includesvalue:
+            logging.info('WARNING: Includes produce non-empty output')
+        self.pp.out = None
+
+    def finalizeJar(self, jarPath, chromebasepath, register, doZip=True):
+        '''Helper method to write out the chrome registration entries to
+         jarfile.manifest or chrome.manifest, or both.
+
+        The actual file processing is done in updateManifest.
+        '''
+
+        # rewrite the manifest, if entries given
+        if not register:
+            return
 
-    Only use this for #defines, the includes shouldn't generate
-    content.
-    '''
-    self.pp.out = StringIO()
-    for inc in includes:
-      self.pp.do_include(inc)
-    includesvalue = self.pp.out.getvalue()
-    if includesvalue:
-      logging.info("WARNING: Includes produce non-empty output")
-    self.pp.out = None
-    pass
+        chromeManifest = os.path.join(os.path.dirname(jarPath), '..',
+                'chrome.manifest')
 
-  def finalizeJar(self, jarPath, chromebasepath, register,
-                  doZip=True):
-    '''Helper method to write out the chrome registration entries to
-    jarfile.manifest or chrome.manifest, or both.
+        if self.useJarfileManifest:
+            self.updateManifest(jarPath + '.manifest',
+                                chromebasepath.format(''), register)
+            addEntriesToListFile(chromeManifest,
+                                 ['manifest chrome/{0}.manifest'.format(os.path.basename(jarPath))])
+        if self.useChromeManifest:
+            self.updateManifest(chromeManifest,
+                                chromebasepath.format('chrome/'),
+                                register)
+
+        # If requested, add a root chrome manifest entry (assumed to be in the parent directory
+        # of chromeManifest) with the application specific id. In cases where we're building
+        # lang packs, the root manifest must know about application sub directories.
 
-    The actual file processing is done in updateManifest.
-    '''
-    # rewrite the manifest, if entries given
-    if not register:
-      return
-
-    chromeManifest = os.path.join(os.path.dirname(jarPath),
-                                  '..', 'chrome.manifest')
+        if self.rootManifestAppId:
+            rootChromeManifest = \
+                os.path.join(os.path.normpath(os.path.dirname(chromeManifest)),
+                             '..', 'chrome.manifest')
+            rootChromeManifest = os.path.normpath(rootChromeManifest)
+            chromeDir = \
+                os.path.basename(os.path.dirname(os.path.normpath(chromeManifest)))
+            logging.info("adding '%s' entry to root chrome manifest appid=%s"
+                          % (chromeDir, self.rootManifestAppId))
+            addEntriesToListFile(rootChromeManifest,
+                                 ['manifest %s/chrome.manifest application=%s'
+                                  % (chromeDir,
+                                 self.rootManifestAppId)])
 
-    if self.useJarfileManifest:
-      self.updateManifest(jarPath + '.manifest', chromebasepath.format(''),
-                          register)
-      addEntriesToListFile(chromeManifest, ['manifest chrome/{0}.manifest'
-                                            .format(os.path.basename(jarPath))])
-    if self.useChromeManifest:
-      self.updateManifest(chromeManifest, chromebasepath.format('chrome/'),
-                          register)
+    def updateManifest(self, manifestPath, chromebasepath, register):
+        '''updateManifest replaces the % in the chrome registration entries
+        with the given chrome base path, and updates the given manifest file.
+        '''
 
-    # If requested, add a root chrome manifest entry (assumed to be in the parent directory
-    # of chromeManifest) with the application specific id. In cases where we're building
-    # lang packs, the root manifest must know about application sub directories.
-    if self.rootManifestAppId:
-      rootChromeManifest = os.path.join(os.path.normpath(os.path.dirname(chromeManifest)),
-                                        '..', 'chrome.manifest')
-      rootChromeManifest = os.path.normpath(rootChromeManifest)
-      chromeDir = os.path.basename(os.path.dirname(os.path.normpath(chromeManifest)))
-      logging.info("adding '%s' entry to root chrome manifest appid=%s" % (chromeDir, self.rootManifestAppId))
-      addEntriesToListFile(rootChromeManifest, ['manifest %s/chrome.manifest application=%s' % (chromeDir, self.rootManifestAppId)])
+        lock = lock_file(manifestPath + '.lck')
+        try:
+            myregister = dict.fromkeys(map(lambda s: s.replace('%',
+                    chromebasepath), register.iterkeys()))
+            manifestExists = os.path.isfile(manifestPath)
+            mode = manifestExists and 'r+b' or 'wb'
+            mf = open(manifestPath, mode)
+            if manifestExists:
+                # import previous content into hash, ignoring empty ones and comments
+                imf = re.compile('(#.*)?$')
+                for l in re.split('[\r\n]+', mf.read()):
+                    if imf.match(l):
+                        continue
+                    myregister[l] = None
+                mf.seek(0)
+            for k in myregister.iterkeys():
+                mf.write(k + os.linesep)
+            mf.close()
+        finally:
+            lock = None
+
+    def makeJar(self, infile, jardir):
+        '''makeJar is the main entry point to JarMaker.
+
+        It takes the input file, the output directory, the source dirs and the
+        top source dir as argument, and optionally the l10n dirs.
+        '''
 
-  def updateManifest(self, manifestPath, chromebasepath, register):
-    '''updateManifest replaces the % in the chrome registration entries
-    with the given chrome base path, and updates the given manifest file.
-    '''
-    lock = lock_file(manifestPath + '.lck')
-    try:
-      myregister = dict.fromkeys(map(lambda s: s.replace('%', chromebasepath),
-                                     register.iterkeys()))
-      manifestExists = os.path.isfile(manifestPath)
-      mode = (manifestExists and 'r+b') or 'wb'
-      mf = open(manifestPath, mode)
-      if manifestExists:
-        # import previous content into hash, ignoring empty ones and comments
-        imf = re.compile('(#.*)?$')
-        for l in re.split('[\r\n]+', mf.read()):
-          if imf.match(l):
-            continue
-          myregister[l] = None
-        mf.seek(0)
-      for k in myregister.iterkeys():
-        mf.write(k + os.linesep)
-      mf.close()
-    finally:
-      lock = None
+        # making paths absolute, guess srcdir if file and add to sourcedirs
+        _normpath = lambda p: os.path.normpath(os.path.abspath(p))
+        self.topsourcedir = _normpath(self.topsourcedir)
+        self.sourcedirs = [_normpath(p) for p in self.sourcedirs]
+        if self.localedirs:
+            self.localedirs = [_normpath(p) for p in self.localedirs]
+        elif self.relativesrcdir:
+            self.localedirs = \
+                self.generateLocaleDirs(self.relativesrcdir)
+        if isinstance(infile, basestring):
+            logging.info('processing ' + infile)
+            self.sourcedirs.append(_normpath(os.path.dirname(infile)))
+        pp = self.pp.clone()
+        pp.out = StringIO()
+        pp.do_include(infile)
+        lines = PushbackIter(pp.out.getvalue().splitlines())
+        try:
+            while True:
+                l = lines.next()
+                m = self.jarline.match(l)
+                if not m:
+                    raise RuntimeError(l)
+                if m.group('jarfile') is None:
+                    # comment
+                    continue
+                self.processJarSection(m.group('jarfile'), lines,
+                        jardir)
+        except StopIteration:
+            # we read the file
+            pass
+        return
 
-  def makeJar(self, infile, jardir):
-    '''makeJar is the main entry point to JarMaker.
+    def generateLocaleDirs(self, relativesrcdir):
+        if os.path.basename(relativesrcdir) == 'locales':
+            # strip locales
+            l10nrelsrcdir = os.path.dirname(relativesrcdir)
+        else:
+            l10nrelsrcdir = relativesrcdir
+        locdirs = []
 
-    It takes the input file, the output directory, the source dirs and the
-    top source dir as argument, and optionally the l10n dirs.
-    '''
-    # making paths absolute, guess srcdir if file and add to sourcedirs
-    _normpath = lambda p: os.path.normpath(os.path.abspath(p))
-    self.topsourcedir = _normpath(self.topsourcedir)
-    self.sourcedirs = [_normpath(p) for p in self.sourcedirs]
-    if self.localedirs:
-      self.localedirs = [_normpath(p) for p in self.localedirs]
-    elif self.relativesrcdir:
-      self.localedirs = self.generateLocaleDirs(self.relativesrcdir)
-    if isinstance(infile, basestring):
-      logging.info("processing " + infile)
-      self.sourcedirs.append(_normpath(os.path.dirname(infile)))
-    pp = self.pp.clone()
-    pp.out = StringIO()
-    pp.do_include(infile)
-    lines = PushbackIter(pp.out.getvalue().splitlines())
-    try:
-      while True:
-        l = lines.next()
-        m = self.jarline.match(l)
-        if not m:
-          raise RuntimeError(l)
-        if m.group('jarfile') is None:
-          # comment
-          continue
-        self.processJarSection(m.group('jarfile'), lines, jardir)
-    except StopIteration:
-      # we read the file
-      pass
-    return
+        # generate locales dirs, merge, l10nbase, en-US
+        if self.l10nmerge:
+            locdirs.append(os.path.join(self.l10nmerge, l10nrelsrcdir))
+        if self.l10nbase:
+            locdirs.append(os.path.join(self.l10nbase, l10nrelsrcdir))
+        if self.l10nmerge or not self.l10nbase:
+            # add en-US if we merge, or if it's not l10n
+            locdirs.append(os.path.join(self.topsourcedir,
+                           relativesrcdir, 'en-US'))
+        return locdirs
+
+    def processJarSection(self, jarfile, lines, jardir):
+        '''Internal method called by makeJar to actually process a section
+        of a jar.mn file.
+
+        jarfile is the basename of the jarfile or the directory name for
+        flat output, lines is a PushbackIter of the lines of jar.mn,
+        the remaining options are carried over from makeJar.
+        '''
+
+        # chromebasepath is used for chrome registration manifests
+        # {0} is getting replaced with chrome/ for chrome.manifest, and with
+        # an empty string for jarfile.manifest
+
+        chromebasepath = '{0}' + os.path.basename(jarfile)
+        if self.outputFormat == 'jar':
+            chromebasepath = 'jar:' + chromebasepath + '.jar!'
+        chromebasepath += '/'
+
+        jarfile = os.path.join(jardir, jarfile)
+        jf = None
+        if self.outputFormat == 'jar':
+            # jar
+            jarfilepath = jarfile + '.jar'
+            try:
+                os.makedirs(os.path.dirname(jarfilepath))
+            except OSError, error:
+                if error.errno != errno.EEXIST:
+                    raise
+            jf = ZipFile(jarfilepath, 'a', lock=True)
+            outHelper = self.OutputHelper_jar(jf)
+        else:
+            outHelper = getattr(self, 'OutputHelper_'
+                                + self.outputFormat)(jarfile)
+        register = {}
+
+        # This loop exits on either
+        # - the end of the jar.mn file
+        # - an line in the jar.mn file that's not part of a jar section
+        # - on an exception raised, close the jf in that case in a finally
 
-  def generateLocaleDirs(self, relativesrcdir):
-    if os.path.basename(relativesrcdir) == 'locales':
-      # strip locales
-      l10nrelsrcdir = os.path.dirname(relativesrcdir)
-    else:
-      l10nrelsrcdir = relativesrcdir
-    locdirs = []
-    # generate locales dirs, merge, l10nbase, en-US
-    if self.l10nmerge:
-      locdirs.append(os.path.join(self.l10nmerge, l10nrelsrcdir))
-    if self.l10nbase:
-      locdirs.append(os.path.join(self.l10nbase, l10nrelsrcdir))
-    if self.l10nmerge or not self.l10nbase:
-      # add en-US if we merge, or if it's not l10n
-      locdirs.append(os.path.join(self.topsourcedir, relativesrcdir, 'en-US'))
-    return locdirs
+        try:
+            while True:
+                try:
+                    l = lines.next()
+                except StopIteration:
+                    # we're done with this jar.mn, and this jar section
+                    self.finalizeJar(jarfile, chromebasepath, register)
+                    if jf is not None:
+                        jf.close()
 
-  def processJarSection(self, jarfile, lines, jardir):
-    '''Internal method called by makeJar to actually process a section
-    of a jar.mn file.
+                    # reraise the StopIteration for makeJar
+                    raise
+                if self.ignore.match(l):
+                    continue
+                m = self.relsrcline.match(l)
+                if m:
+                    relativesrcdir = m.group('relativesrcdir')
+                    self.localedirs = \
+                        self.generateLocaleDirs(relativesrcdir)
+                    continue
+                m = self.regline.match(l)
+                if m:
+                    rline = m.group(1)
+                    register[rline] = 1
+                    continue
+                m = self.entryline.match(l)
+                if not m:
+                    # neither an entry line nor chrome reg, this jar section is done
+                    self.finalizeJar(jarfile, chromebasepath, register)
+                    if jf is not None:
+                        jf.close()
+                    lines.pushback(l)
+                    return
+                self._processEntryLine(m, outHelper, jf)
+        finally:
+            if jf is not None:
+                jf.close()
+        return
 
-    jarfile is the basename of the jarfile or the directory name for
-    flat output, lines is a PushbackIter of the lines of jar.mn,
-    the remaining options are carried over from makeJar.
-    '''
+    def _processEntryLine(self, m, outHelper, jf):
+        out = m.group('output')
+        src = m.group('source') or os.path.basename(out)
+
+        # pick the right sourcedir -- l10n, topsrc or src
 
-    # chromebasepath is used for chrome registration manifests
-    # {0} is getting replaced with chrome/ for chrome.manifest, and with
-    # an empty string for jarfile.manifest
-    chromebasepath = '{0}' + os.path.basename(jarfile)
-    if self.outputFormat == 'jar':
-      chromebasepath = 'jar:' + chromebasepath + '.jar!'
-    chromebasepath += '/'
+        if m.group('locale'):
+            src_base = self.localedirs
+        elif src.startswith('/'):
+            # path/in/jar/file_name.xul     (/path/in/sourcetree/file_name.xul)
+            # refers to a path relative to topsourcedir, use that as base
+            # and strip the leading '/'
+            src_base = [self.topsourcedir]
+            src = src[1:]
+        else:
+            # use srcdirs and the objdir (current working dir) for relative paths
+            src_base = self.sourcedirs + [os.getcwd()]
 
-    jarfile = os.path.join(jardir, jarfile)
-    jf = None
-    if self.outputFormat == 'jar':
-      #jar
-      jarfilepath = jarfile + '.jar'
-      try:
-        os.makedirs(os.path.dirname(jarfilepath))
-      except OSError as error:
-        if error.errno != errno.EEXIST:
-          raise
-      jf = ZipFile(jarfilepath, 'a', lock = True)
-      outHelper = self.OutputHelper_jar(jf)
-    else:
-      outHelper = getattr(self, 'OutputHelper_' + self.outputFormat)(jarfile)
-    register = {}
-    # This loop exits on either
-    # - the end of the jar.mn file
-    # - an line in the jar.mn file that's not part of a jar section
-    # - on an exception raised, close the jf in that case in a finally
-    try:
-      while True:
-        try:
-          l = lines.next()
-        except StopIteration:
-          # we're done with this jar.mn, and this jar section
-          self.finalizeJar(jarfile, chromebasepath, register)
-          if jf is not None:
-            jf.close()
-          # reraise the StopIteration for makeJar
-          raise
-        if self.ignore.match(l):
-          continue
-        m = self.relsrcline.match(l)
-        if m:
-          relativesrcdir = m.group('relativesrcdir')
-          self.localedirs = self.generateLocaleDirs(relativesrcdir)
-          continue
-        m = self.regline.match(l)
-        if  m:
-          rline = m.group(1)
-          register[rline] = 1
-          continue
-        m = self.entryline.match(l)
-        if not m:
-          # neither an entry line nor chrome reg, this jar section is done
-          self.finalizeJar(jarfile, chromebasepath, register)
-          if jf is not None:
-            jf.close()
-          lines.pushback(l)
-          return
-        self._processEntryLine(m, outHelper, jf)
-    finally:
-      if jf is not None:
-        jf.close()
-    return
+        # check if the source file exists
+        realsrc = None
+        for _srcdir in src_base:
+            if os.path.isfile(os.path.join(_srcdir, src)):
+                realsrc = os.path.join(_srcdir, src)
+                break
+        if realsrc is None:
+            if jf is not None:
+                jf.close()
+            raise RuntimeError('File "{0}" not found in {1}'.format(src,
+                               ', '.join(src_base)))
+        if m.group('optPreprocess'):
+            outf = outHelper.getOutput(out)
+            inf = open(realsrc)
+            pp = self.pp.clone()
+            if src[-4:] == '.css':
+                pp.setMarker('%')
+            pp.out = outf
+            pp.do_include(inf)
+            pp.warnUnused(realsrc)
+            outf.close()
+            inf.close()
+            return
+
+        # copy or symlink if newer or overwrite
+
+        if m.group('optOverwrite') or getModTime(realsrc) \
+            > outHelper.getDestModTime(m.group('output')):
+            if self.outputFormat == 'symlink':
+                outHelper.symlink(realsrc, out)
+                return
+            outf = outHelper.getOutput(out)
+
+            # open in binary mode, this can be images etc
+
+            inf = open(realsrc, 'rb')
+            outf.write(inf.read())
+            outf.close()
+            inf.close()
+
+    class OutputHelper_jar(object):
+        '''Provide getDestModTime and getOutput for a given jarfile.'''
+
+        def __init__(self, jarfile):
+            self.jarfile = jarfile
+
+        def getDestModTime(self, aPath):
+            try:
+                info = self.jarfile.getinfo(aPath)
+                return info.date_time
+            except:
+                return 0
+
+        def getOutput(self, name):
+            return ZipEntry(name, self.jarfile)
 
-  def _processEntryLine(self, m, outHelper, jf):
-      out = m.group('output')
-      src = m.group('source') or os.path.basename(out)
-      # pick the right sourcedir -- l10n, topsrc or src
-      if m.group('locale'):
-        src_base = self.localedirs
-      elif src.startswith('/'):
-        # path/in/jar/file_name.xul     (/path/in/sourcetree/file_name.xul)
-        # refers to a path relative to topsourcedir, use that as base
-        # and strip the leading '/'
-        src_base = [self.topsourcedir]
-        src = src[1:]
-      else:
-        # use srcdirs and the objdir (current working dir) for relative paths
-        src_base = self.sourcedirs + [os.getcwd()]
-      # check if the source file exists
-      realsrc = None
-      for _srcdir in src_base:
-        if os.path.isfile(os.path.join(_srcdir, src)):
-          realsrc = os.path.join(_srcdir, src)
-          break
-      if realsrc is None:
-        if jf is not None:
-          jf.close()
-        raise RuntimeError('File "{0}" not found in {1}'
-                           .format(src, ', '.join(src_base)))
-      if m.group('optPreprocess'):
-        outf = outHelper.getOutput(out)
-        inf = open(realsrc)
-        pp = self.pp.clone()
-        if src[-4:] == '.css':
-          pp.setMarker('%')
-        pp.out = outf
-        pp.do_include(inf)
-        pp.warnUnused(realsrc)
-        outf.close()
-        inf.close()
-        return
-      # copy or symlink if newer or overwrite
-      if (m.group('optOverwrite')
-          or (getModTime(realsrc) >
-              outHelper.getDestModTime(m.group('output')))):
-        if self.outputFormat == 'symlink':
-          outHelper.symlink(realsrc, out)
-          return
-        outf = outHelper.getOutput(out)
-        # open in binary mode, this can be images etc
-        inf = open(realsrc, 'rb')
-        outf.write(inf.read())
-        outf.close()
-        inf.close()
+    class OutputHelper_flat(object):
+        '''Provide getDestModTime and getOutput for a given flat
+        output directory. The helper method ensureDirFor is used by
+        the symlink subclass.
+        '''
+
+        def __init__(self, basepath):
+            self.basepath = basepath
+
+        def getDestModTime(self, aPath):
+            return getModTime(os.path.join(self.basepath, aPath))
+
+        def getOutput(self, name):
+            out = self.ensureDirFor(name)
+
+            # remove previous link or file
+            try:
+                os.remove(out)
+            except OSError, e:
+                if e.errno != errno.ENOENT:
+                    raise
+            return open(out, 'wb')
+
+        def ensureDirFor(self, name):
+            out = os.path.join(self.basepath, name)
+            outdir = os.path.dirname(out)
+            if not os.path.isdir(outdir):
+                try:
+                    os.makedirs(outdir)
+                except OSError, error:
+                    if error.errno != errno.EEXIST:
+                        raise
+            return out
+
+    class OutputHelper_symlink(OutputHelper_flat):
+        '''Subclass of OutputHelper_flat that provides a helper for
+        creating a symlink including creating the parent directories.
+        '''
+
+        def symlink(self, src, dest):
+            out = self.ensureDirFor(dest)
+
+            # remove previous link or file
+            try:
+                os.remove(out)
+            except OSError, e:
+                if e.errno != errno.ENOENT:
+                    raise
+            if sys.platform != 'win32':
+                os.symlink(src, out)
+            else:
+                # On Win32, use ctypes to create a hardlink
+                rv = CreateHardLink(out, src, None)
+                if rv == 0:
+                    raise WinError()
 
 
-  class OutputHelper_jar(object):
-    '''Provide getDestModTime and getOutput for a given jarfile.
-    '''
-    def __init__(self, jarfile):
-      self.jarfile = jarfile
-    def getDestModTime(self, aPath):
-      try :
-        info = self.jarfile.getinfo(aPath)
-        return info.date_time
-      except:
-        return 0
-    def getOutput(self, name):
-      return ZipEntry(name, self.jarfile)
-
-  class OutputHelper_flat(object):
-    '''Provide getDestModTime and getOutput for a given flat
-    output directory. The helper method ensureDirFor is used by
-    the symlink subclass.
-    '''
-    def __init__(self, basepath):
-      self.basepath = basepath
-    def getDestModTime(self, aPath):
-      return getModTime(os.path.join(self.basepath, aPath))
-    def getOutput(self, name):
-      out = self.ensureDirFor(name)
-      # remove previous link or file
-      try:
-        os.remove(out)
-      except OSError as e:
-        if e.errno != errno.ENOENT:
-          raise
-      return open(out, 'wb')
-    def ensureDirFor(self, name):
-      out = os.path.join(self.basepath, name)
-      outdir = os.path.dirname(out)
-      if not os.path.isdir(outdir):
-        try:
-          os.makedirs(outdir)
-        except OSError as error:
-          if error.errno != errno.EEXIST:
-            raise
-      return out
-
-  class OutputHelper_symlink(OutputHelper_flat):
-    '''Subclass of OutputHelper_flat that provides a helper for
-    creating a symlink including creating the parent directories.
-    '''
-    def symlink(self, src, dest):
-      out = self.ensureDirFor(dest)
-      # remove previous link or file
-      try:
-        os.remove(out)
-      except OSError as e:
-        if e.errno != errno.ENOENT:
-          raise
-      if sys.platform != "win32":
-        os.symlink(src, out)
-      else:
-        # On Win32, use ctypes to create a hardlink
-        rv = CreateHardLink(out, src, None)
-        if rv == 0:
-          raise WinError()
-
-def main():
-  jm = JarMaker()
-  p = jm.getCommandLineParser()
-  (options, args) = p.parse_args()
-  jm.processIncludes(options.I)
-  jm.outputFormat = options.f
-  jm.sourcedirs = options.s
-  jm.topsourcedir = options.t
-  if options.e:
-    jm.useChromeManifest = True
-    jm.useJarfileManifest = False
-  if options.bothManifests:
-    jm.useChromeManifest = True
-    jm.useJarfileManifest = True
-  if options.l10n_base:
-    if not options.relativesrcdir:
-      p.error('relativesrcdir required when using l10n-base')
-    if options.l10n_src:
-      p.error('both l10n-src and l10n-base are not supported')
-    jm.l10nbase = options.l10n_base
-    jm.relativesrcdir = options.relativesrcdir
-    jm.l10nmerge = options.locale_mergedir
-    if jm.l10nmerge and not os.path.isdir(jm.l10nmerge):
-      logging.warning("WARNING: --locale-mergedir passed, but '%s' does not "
-                      "exist. Ignore this message if the locale is complete.")
-  elif options.locale_mergedir:
-    p.error('l10n-base required when using locale-mergedir')
-  jm.localedirs = options.l10n_src
-  if options.root_manifest_entry_appid:
-    jm.rootManifestAppId = options.root_manifest_entry_appid
-  noise = logging.INFO
-  if options.verbose is not None:
-    noise = (options.verbose and logging.DEBUG) or logging.WARN
-  if sys.version_info[:2] > (2,3):
-    logging.basicConfig(format = "%(message)s")
-  else:
-    logging.basicConfig()
-  logging.getLogger().setLevel(noise)
-  topsrc = options.t
-  topsrc = os.path.normpath(os.path.abspath(topsrc))
-  if not args:
-    infile = sys.stdin
-  else:
-    infile,  = args
-  jm.makeJar(infile, options.j)
-
-if __name__ == "__main__":
-  main()
+def main(args=None):
+    args = args or sys.argv
+    jm = JarMaker()
+    p = jm.getCommandLineParser()
+    (options, args) = p.parse_args(args)
+    jm.processIncludes(options.I)
+    jm.outputFormat = options.f
+    jm.sourcedirs = options.s
+    jm.topsourcedir = options.t
+    if options.e:
+        jm.useChromeManifest = True
+        jm.useJarfileManifest = False
+    if options.bothManifests:
+        jm.useChromeManifest = True
+        jm.useJarfileManifest = True
+    if options.l10n_base:
+        if not options.relativesrcdir:
+            p.error('relativesrcdir required when using l10n-base')
+        if options.l10n_src:
+            p.error('both l10n-src and l10n-base are not supported')
+        jm.l10nbase = options.l10n_base
+        jm.relativesrcdir = options.relativesrcdir
+        jm.l10nmerge = options.locale_mergedir
+        if jm.l10nmerge and not os.path.isdir(jm.l10nmerge):
+            logging.warning("WARNING: --locale-mergedir passed, but '%s' does not exist. Ignore this message if the locale is complete."
+                            )
+    elif options.locale_mergedir:
+        p.error('l10n-base required when using locale-mergedir')
+    jm.localedirs = options.l10n_src
+    if options.root_manifest_entry_appid:
+        jm.rootManifestAppId = options.root_manifest_entry_appid
+    noise = logging.INFO
+    if options.verbose is not None:
+        noise = options.verbose and logging.DEBUG or logging.WARN
+    if sys.version_info[:2] > (2, 3):
+        logging.basicConfig(format='%(message)s')
+    else:
+        logging.basicConfig()
+    logging.getLogger().setLevel(noise)
+    topsrc = options.t
+    topsrc = os.path.normpath(os.path.abspath(topsrc))
+    if not args:
+        infile = sys.stdin
+    else:
+        (infile, ) = args
+    jm.makeJar(infile, options.j)
--- a/python/mozbuild/mozbuild/mach_commands.py
+++ b/python/mozbuild/mozbuild/mach_commands.py
@@ -18,16 +18,17 @@ from mach.decorators import (
 
 from mach.mixin.logging import LoggingMixin
 
 from mozbuild.base import (
     MachCommandBase,
     MozbuildObject,
     MozconfigFindException,
     MozconfigLoadException,
+    ObjdirMismatchException,
 )
 
 
 BUILD_WHAT_HELP = '''
 What to build. Can be a top-level make target or a relative directory. If
 multiple options are provided, they will be built serially. Takes dependency
 information from `topsrcdir/build/dumbmake-dependencies` to build additional
 targets as needed. BUILDING ONLY PARTS OF THE TREE CAN RESULT IN BAD TREE
@@ -829,36 +830,42 @@ class Makefiles(MachCommandBase):
 
     def _makefile_ins(self):
         for root, dirs, files in os.walk(self.topsrcdir):
             for f in files:
                 if f == 'Makefile.in':
                     yield os.path.join(root, f)
 
 @CommandProvider
-class MachDebug(object):
-    def __init__(self, context):
-        self.context = context
-
+class MachDebug(MachCommandBase):
     @Command('environment', category='build-dev',
         description='Show info about the mach and build environment.')
     @CommandArgument('--verbose', '-v', action='store_true',
         help='Print verbose output.')
     def environment(self, verbose=False):
         import platform
         print('platform:\n\t%s' % platform.platform())
         print('python version:\n\t%s' % sys.version)
         print('python prefix:\n\t%s' % sys.prefix)
-        print('mach cwd:\n\t%s' % self.context.cwd)
+        print('mach cwd:\n\t%s' % self._mach_context.cwd)
         print('os cwd:\n\t%s' % os.getcwd())
-        print('mach directory:\n\t%s' % self.context.topdir)
-        print('state directory:\n\t%s' % self.context.state_dir)
+        print('mach directory:\n\t%s' % self._mach_context.topdir)
+        print('state directory:\n\t%s' % self._mach_context.state_dir)
 
-        mb = MozbuildObject(self.context.topdir, self.context.settings,
-            self.context.log_manager)
+        try:
+            mb = MozbuildObject.from_environment(cwd=self._mach_context.cwd)
+        except ObjdirMismatchException as e:
+            print('Ambiguous object directory detected. We detected that '
+                'both %s and %s could be object directories. This is '
+                'typically caused by having a mozconfig pointing to a '
+                'different object directory from the current working '
+                'directory. To solve this problem, ensure you do not have a '
+                'default mozconfig in searched paths.' % (e.objdir1,
+                    e.objdir2))
+            return 1
 
         mozconfig = None
 
         try:
             mozconfig = mb.mozconfig
             print('mozconfig path:\n\t%s' % mozconfig['path'])
         except MozconfigFindException as e:
             print('Unable to find mozconfig: %s' % e.message)
--- a/python/mozbuild/mozbuild/test/test_base.py
+++ b/python/mozbuild/mozbuild/test/test_base.py
@@ -195,17 +195,17 @@ class TestMozbuildObject(unittest.TestCa
 
             os.chdir(topobjdir)
 
             class MockMachContext(object):
                 pass
 
             context = MockMachContext()
             context.cwd = topobjdir
-            context.topdir = topobjdir
+            context.topdir = topsrcdir
             context.settings = None
             context.log_manager = None
 
             o = MachCommandBase(context)
 
             self.assertEqual(o.topobjdir, topobjdir)
             self.assertEqual(o.topsrcdir, topsrcdir)
 
rename from config/tests/unit-JarMaker.py
rename to python/mozbuild/mozbuild/test/test_jarmaker.py
--- a/config/tests/unit-JarMaker.py
+++ b/python/mozbuild/mozbuild/test/test_jarmaker.py
@@ -1,19 +1,25 @@
+# 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/.
+
 from __future__ import print_function
 import unittest
 
 import os, sys, os.path, time, inspect
 from filecmp import dircmp
 from tempfile import mkdtemp
 from shutil import rmtree, copy2
 from StringIO import StringIO
 from zipfile import ZipFile
 import mozunit
-from JarMaker import JarMaker
+
+from mozbuild.jar import JarMaker
+
 
 if sys.platform == "win32":
     import ctypes
     from ctypes import POINTER, WinError
     DWORD = ctypes.c_ulong
     LPDWORD = POINTER(DWORD)
     HANDLE = ctypes.c_void_p
     GENERIC_READ = 0x80000000
--- a/toolkit/devtools/apps/tests/Makefile.in
+++ b/toolkit/devtools/apps/tests/Makefile.in
@@ -2,17 +2,16 @@
 # 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/.
 
 # The mochitest doesn't work on fennec yet
 ifneq (android,$(MOZ_WIDGET_TOOLKIT))
 MOCHITEST_FILES = \
     test_webapps_actor.html \
     debugger-protocol-helper.js \
-    data/ \
     redirect.sjs \
     $(NULL)
 
 MOCHITEST_DATA_FILES = \
     data/app-redirect.zip \
     data/app-updated.zip \
     data/app.zip \
     $(NULL)
--- a/toolkit/devtools/server/actors/script.js
+++ b/toolkit/devtools/server/actors/script.js
@@ -462,16 +462,23 @@ ThreadActor.prototype = {
   get sources() {
     if (!this._sources) {
       this._sources = new ThreadSources(this, this._options.useSourceMaps,
                                         this._allowSource, this.onNewSource);
     }
     return this._sources;
   },
 
+  get youngestFrame() {
+    if (!this.state == "paused") {
+      return null;
+    }
+    return this.dbg.getNewestFrame();
+  },
+
   _prettyPrintWorker: null,
   get prettyPrintWorker() {
     if (!this._prettyPrintWorker) {
       this._prettyPrintWorker = new ChromeWorker(
         "resource://gre/modules/devtools/server/actors/pretty-print-worker.js");
 
       this._prettyPrintWorker.addEventListener(
         "error", this._onPrettyPrintError, false);
@@ -1174,20 +1181,16 @@ ThreadActor.prototype = {
                message: "Evaluation frame not found" };
     }
 
     if (!frame.environment) {
       return { error: "notDebuggee",
                message: "cannot access the environment of this frame." };
     }
 
-    // We'll clobber the youngest frame if the eval causes a pause, so
-    // save our frame now to be restored after eval returns.
-    // XXX: or we could just start using dbg.getNewestFrame() now that it
-    // works as expected.
     let youngest = this.youngestFrame;
 
     // Put ourselves back in the running state and inform the client.
     let resumedPacket = this._resumed();
     this.conn.send(resumedPacket);
 
     // Run the expression.
     // XXX: test syntax errors
@@ -1733,20 +1736,16 @@ ThreadActor.prototype = {
       for (let [,bp] of this._hiddenBreakpoints) {
         bp.onDelete();
       }
       this._hiddenBreakpoints.clear();
     }
 
     this._state = "paused";
 
-    // Save the pause frame (if any) as the youngest frame for
-    // stack viewing.
-    this.youngestFrame = aFrame;
-
     // Create the actor pool that will hold the pause actor and its
     // children.
     dbg_assert(!this._pausePool, "No pause pool should exist yet");
     this._pausePool = new ActorPool(this.conn);
     this.conn.addActorPool(this._pausePool);
 
     // Give children of the pause pool a quick link back to the
     // thread...
@@ -1778,17 +1777,16 @@ ThreadActor.prototype = {
   _resumed: function TA_resumed() {
     this._state = "running";
 
     // Drop the actors in the pause actor pool.
     this.conn.removeActorPool(this._pausePool);
 
     this._pausePool = null;
     this._pauseActor = null;
-    this.youngestFrame = null;
 
     return { from: this.actorID, type: "resumed" };
   },
 
   /**
    * Expire frame actors for frames that have been popped.
    *
    * @returns A list of actor IDs whose frames have been popped.
@@ -4019,17 +4017,17 @@ function getOffsetColumn(aOffset, aScrip
  * frame does not have a script, the location's properties are all null.
  *
  * @param Debugger.Frame aFrame
  *        The frame whose location we are getting.
  * @returns Object
  *          Returns an object of the form { url, line, column }
  */
 function getFrameLocation(aFrame) {
-  if (!aFrame.script) {
+  if (!aFrame || !aFrame.script) {
     return { url: null, line: null, column: null };
   }
   return {
     url: aFrame.script.url,
     line: aFrame.script.getOffsetLine(aFrame.offset),
     column: getOffsetColumn(aFrame.offset, aFrame.script)
   }
 }
--- a/toolkit/devtools/server/actors/tracer.js
+++ b/toolkit/devtools/server/actors/tracer.js
@@ -271,28 +271,38 @@ TraceActor.prototype = {
 
     this.conn.send(packet);
   },
 
   /**
    * Called by the engine when a frame is exited. Sends an unsolicited packet to
    * the client carrying requested trace information.
    *
-   * @param aValue object
+   * @param aCompletion object
    *        The debugger completion value for the frame.
    */
-  onExitFrame: function(aValue) {
+  onExitFrame: function(aCompletion) {
     let packet = {
       from: this.actorID,
       type: "exitedFrame",
-      sequence: this._sequence++
+      sequence: this._sequence++,
     };
 
+    if (!aCompletion) {
+      packet.why = "terminated";
+    } else if (aCompletion.hasOwnProperty("return")) {
+      packet.why = "return";
+    } else if (aCompletion.hasOwnProperty("yield")) {
+      packet.why = "yield";
+    } else {
+      packet.why = "throw";
+    }
+
     this._handleEvent(TraceTypes.Events.exitFrame, packet, {
-      value: aValue,
+      value: aCompletion,
       startTime: this._startTime
     });
 
     this.conn.send(packet);
   }
 };
 
 /**
new file mode 100644
--- /dev/null
+++ b/toolkit/devtools/server/tests/unit/test_trace_actor-07.js
@@ -0,0 +1,96 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests that the exit frame packets get the correct `why` value.
+ */
+
+let { defer } = devtools.require("sdk/core/promise");
+
+var gDebuggee;
+var gClient;
+var gTraceClient;
+
+function run_test()
+{
+  initTestTracerServer();
+  gDebuggee = addTestGlobal("test-tracer-actor");
+  gClient = new DebuggerClient(DebuggerServer.connectPipe());
+  gClient.connect(function() {
+    attachTestTab(gClient, "test-tracer-actor", function(aResponse, aTabClient) {
+      gClient.attachTracer(aResponse.traceActor, function(aResponse, aTraceClient) {
+        gTraceClient = aTraceClient;
+        test_exit_frame_whys();
+      });
+    });
+  });
+  do_test_pending();
+}
+
+function test_exit_frame_whys()
+{
+  gTraceClient.addListener("exitedFrame", check_packet);
+
+  start_trace()
+    .then(eval_code)
+    .then(stop_trace)
+    .then(function() {
+      finishClient(gClient);
+    }).then(null, error => {
+      do_check_true(false, "Should not get an error, got: " + error);
+    });
+}
+
+function start_trace()
+{
+  let deferred = defer();
+  gTraceClient.startTrace(["name"], null, function() { deferred.resolve(); });
+  return deferred.promise;
+}
+
+function eval_code()
+{
+  gDebuggee.eval("(" + function() {
+    function thrower() {
+      throw new Error();
+    }
+
+    function* yielder() {
+      yield 1;
+    }
+
+    function returner() {
+      return 1;
+    }
+
+    try {
+      thrower();
+    } catch(e) {}
+
+    // XXX bug 923729: Can't test yielding yet.
+    // for (let x of yielder()) {
+    //   break;
+    // }
+
+    returner();
+  } + ")()");
+}
+
+function stop_trace()
+{
+  let deferred = defer();
+  gTraceClient.stopTrace(null, function() { deferred.resolve(); });
+  return deferred.promise;
+}
+
+function check_packet(aEvent, { sequence, why })
+{
+  switch(sequence) {
+  case 3:
+    do_check_eq(why, "throw");
+    break;
+  case 5:
+    do_check_eq(why, "return");
+    break;
+  }
+}
--- a/toolkit/devtools/server/tests/unit/xpcshell.ini
+++ b/toolkit/devtools/server/tests/unit/xpcshell.ini
@@ -180,10 +180,11 @@ reason = bug 820380
 [test_unsafeDereference.js]
 [test_add_actors.js]
 [test_trace_actor-01.js]
 [test_trace_actor-02.js]
 [test_trace_actor-03.js]
 [test_trace_actor-04.js]
 [test_trace_actor-05.js]
 [test_trace_actor-06.js]
+[test_trace_actor-07.js]
 [test_ignore_caught_exceptions.js]
 [test_trace_client-01.js]
--- a/widget/BasicEvents.h
+++ b/widget/BasicEvents.h
@@ -424,16 +424,18 @@ enum nsEventStructType
 
 // Pointerlock DOM API
 #define NS_POINTERLOCK_START         5300
 #define NS_POINTERLOCKCHANGE         (NS_POINTERLOCK_START)
 #define NS_POINTERLOCKERROR          (NS_POINTERLOCK_START + 1)
 
 #define NS_WHEEL_EVENT_START         5400
 #define NS_WHEEL_WHEEL               (NS_WHEEL_EVENT_START)
+#define NS_WHEEL_START               (NS_WHEEL_EVENT_START + 1)
+#define NS_WHEEL_STOP                (NS_WHEEL_EVENT_START + 2)
 
 //System time is changed
 #define NS_MOZ_TIME_CHANGE_EVENT     5500
 
 // Network packet events.
 #define NS_NETWORK_EVENT_START       5600
 #define NS_NETWORK_UPLOAD_EVENT      (NS_NETWORK_EVENT_START + 1)
 #define NS_NETWORK_DOWNLOAD_EVENT    (NS_NETWORK_EVENT_START + 2)
--- a/widget/MouseEvents.h
+++ b/widget/MouseEvents.h
@@ -313,17 +313,18 @@ private:
 
 public:
   WidgetWheelEvent(bool aIsTrusted, uint32_t aMessage, nsIWidget* aWidget) :
     WidgetMouseEventBase(aIsTrusted, aMessage, aWidget, NS_WHEEL_EVENT),
     deltaX(0.0), deltaY(0.0), deltaZ(0.0),
     deltaMode(nsIDOMWheelEvent::DOM_DELTA_PIXEL),
     customizedByUserPrefs(false), isMomentum(false), isPixelOnlyDevice(false),
     lineOrPageDeltaX(0), lineOrPageDeltaY(0), scrollType(SCROLL_DEFAULT),
-    overflowDeltaX(0.0), overflowDeltaY(0.0)
+    overflowDeltaX(0.0), overflowDeltaY(0.0),
+    mViewPortIsOverscrolled(false)
   {
   }
 
   // NOTE: deltaX, deltaY and deltaZ may be customized by
   //       mousewheel.*.delta_multiplier_* prefs which are applied by
   //       nsEventStateManager.  So, after widget dispatches this event,
   //       these delta values may have different values than before.
   double deltaX;
@@ -394,32 +395,39 @@ public:
   // NOTE: deltaX, deltaY and deltaZ may be modified by nsEventStateManager.
   //       However, overflowDeltaX and overflowDeltaY indicate unused original
   //       delta values which are not applied the delta_multiplier prefs.
   //       So, if widget wanted to know the actual direction to be scrolled,
   //       it would need to check the deltaX and deltaY.
   double overflowDeltaX;
   double overflowDeltaY;
 
+  // Whether or not the parent of the currently overscrolled frame is the
+  // ViewPort. This is false in situations when an element on the page is being
+  // overscrolled (such as a text field), but true when the 'page' is being
+  // overscrolled.
+  bool mViewPortIsOverscrolled;
+
   void AssignWheelEventData(const WidgetWheelEvent& aEvent, bool aCopyTargets)
   {
     AssignMouseEventBaseData(aEvent, aCopyTargets);
 
     deltaX = aEvent.deltaX;
     deltaY = aEvent.deltaY;
     deltaZ = aEvent.deltaZ;
     deltaMode = aEvent.deltaMode;
     customizedByUserPrefs = aEvent.customizedByUserPrefs;
     isMomentum = aEvent.isMomentum;
     isPixelOnlyDevice = aEvent.isPixelOnlyDevice;
     lineOrPageDeltaX = aEvent.lineOrPageDeltaX;
     lineOrPageDeltaY = aEvent.lineOrPageDeltaY;
     scrollType = aEvent.scrollType;
     overflowDeltaX = aEvent.overflowDeltaX;
     overflowDeltaY = aEvent.overflowDeltaY;
+    mViewPortIsOverscrolled = aEvent.mViewPortIsOverscrolled;
   }
 };
 
 // TODO: Remove following typedef
 typedef WidgetWheelEvent                WheelEvent;
 
 } // namespace mozilla
 
--- a/widget/cocoa/nsChildView.h
+++ b/widget/cocoa/nsChildView.h
@@ -200,16 +200,22 @@ typedef NSInteger NSEventGestureAxis;
 - (void)trackSwipeEventWithOptions:(NSEventSwipeTrackingOptions)options
           dampenAmountThresholdMin:(CGFloat)minDampenThreshold
                                max:(CGFloat)maxDampenThreshold
                       usingHandler:(void (^)(CGFloat gestureAmount, NSEventPhase phase, BOOL isComplete, BOOL *stop))trackingHandler;
 @end
 #endif // #ifdef __LP64__
 #endif // #if !defined(MAC_OS_X_VERSION_10_7) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
 
+#if !defined(MAC_OS_X_VERSION_10_8) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_8
+enum {
+  NSEventPhaseMayBegin    = 0x1 << 5
+};
+#endif // #if !defined(MAC_OS_X_VERSION_10_8) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_8
+
 // Undocumented scrollPhase flag that lets us discern between real scrolls and
 // automatically firing momentum scroll events.
 @interface NSEvent (ScrollPhase)
 // Leopard and SnowLeopard
 - (long long)_scrollPhase;
 // Lion and above
 - (NSEventPhase)momentumPhase;
 @end
@@ -247,16 +253,21 @@ typedef NSInteger NSEventGestureAxis;
   // when acceptsFirstMouse: is called, we store the event here (strong)
   NSEvent* mClickThroughMouseDownEvent;
 
   // rects that were invalidated during a draw, so have pending drawing
   NSMutableArray* mPendingDirtyRects;
   BOOL mPendingFullDisplay;
   BOOL mPendingDisplay;
 
+  // WheelStart/Stop events should always come in pairs. This BOOL records the
+  // last received event so that, when we receive one of the events, we make sure
+  // to send its pair event first, in case we didn't yet for any reason.
+  BOOL mExpectingWheelStop;
+
   // Holds our drag service across multiple drag calls. The reference to the
   // service is obtained when the mouse enters the view and is released when
   // the mouse exits or there is a drop. This prevents us from having to
   // re-establish the connection to the service manager many times per second
   // when handling |draggingUpdated:| messages.
   nsIDragService* mDragService;
 
   NSOpenGLContext *mGLContext;
@@ -285,16 +296,17 @@ typedef NSInteger NSEventGestureAxis;
   float mCumulativeRotation;
 
   BOOL mDidForceRefreshOpenGL;
   BOOL mWaitingForPaint;
 
 #ifdef __LP64__
   // Support for fluid swipe tracking.
   BOOL* mCancelSwipeAnimation;
+  uint32_t mCurrentSwipeDir;
 #endif
 
   // Whether this uses off-main-thread compositing.
   BOOL mUsingOMTCompositor;
 
   // The mask image that's used when painting into the titlebar using basic
   // CGContext painting (i.e. non-accelerated).
   CGImageRef mTopLeftCornerMask;
@@ -349,23 +361,27 @@ typedef NSInteger NSEventGestureAxis;
 // http://cocoadex.com/2008/02/nsevent-modifications-swipe-ro.html
 - (void)swipeWithEvent:(NSEvent *)anEvent;
 - (void)beginGestureWithEvent:(NSEvent *)anEvent;
 - (void)magnifyWithEvent:(NSEvent *)anEvent;
 - (void)smartMagnifyWithEvent:(NSEvent *)anEvent;
 - (void)rotateWithEvent:(NSEvent *)anEvent;
 - (void)endGestureWithEvent:(NSEvent *)anEvent;
 
+- (void)scrollWheel:(NSEvent *)anEvent;
+
 // Helper function for Lion smart magnify events
 + (BOOL)isLionSmartMagnifyEvent:(NSEvent*)anEvent;
 
 // Support for fluid swipe tracking.
 #ifdef __LP64__
 - (void)maybeTrackScrollEventAsSwipe:(NSEvent *)anEvent
-                      scrollOverflow:(double)overflow;
+                     scrollOverflowX:(double)anOverflowX
+                     scrollOverflowY:(double)anOverflowY
+              viewPortIsOverscrolled:(BOOL)aViewPortIsOverscrolled;
 #endif
 
 - (void)setUsingOMTCompositor:(BOOL)aUseOMTC;
 @end
 
 class ChildViewMouseTracker {
 
 public:
--- a/widget/cocoa/nsChildView.mm
+++ b/widget/cocoa/nsChildView.mm
@@ -135,16 +135,18 @@ uint32_t nsChildView::sLastInputEventCou
 
 @interface ChildView(Private)
 
 // sets up our view, attaching it to its owning gecko view
 - (id)initWithFrame:(NSRect)inFrame geckoChild:(nsChildView*)inChild;
 - (void)forceRefreshOpenGL;
 
 // set up a gecko mouse event based on a cocoa mouse event
+- (void) convertCocoaMouseWheelEvent:(NSEvent*)aMouseEvent
+                        toGeckoEvent:(WidgetWheelEvent*)outWheelEvent;
 - (void) convertCocoaMouseEvent:(NSEvent*)aMouseEvent
                    toGeckoEvent:(WidgetInputEvent*)outGeckoEvent;
 
 - (NSMenu*)contextMenu;
 
 - (void)setIsPluginView:(BOOL)aIsPlugin;
 - (void)setPluginEventModel:(NPEventModel)eventModel;
 - (void)setPluginDrawingModel:(NPDrawingModel)drawingModel;
@@ -2772,16 +2774,17 @@ NSEvent* gLastDragMouseDownEvent = nil;
     // We don't support the Quickdraw drawing model any more but it's still
     // the default model for i386 per NPAPI.
     mPluginDrawingModel = NPDrawingModelQuickDraw;
 #else
     mPluginDrawingModel = NPDrawingModelCoreGraphics;
 #endif
     mPendingDisplay = NO;
     mBlockedLastMouseDown = NO;
+    mExpectingWheelStop = NO;
 
     mLastMouseDownEvent = nil;
     mClickThroughMouseDownEvent = nil;
     mDragService = nullptr;
 
     mGestureState = eGestureState_None;
     mCumulativeMagnification = 0.0;
     mCumulativeRotation = 0.0;
@@ -2791,16 +2794,17 @@ NSEvent* gLastDragMouseDownEvent = nil;
     // we call it in drawRect:inContext:, when we know that a draw is in
     // progress.
     mDidForceRefreshOpenGL = NO;
 
     [self setFocusRingType:NSFocusRingTypeNone];
 
 #ifdef __LP64__
     mCancelSwipeAnimation = nil;
+    mCurrentSwipeDir = 0;
 #endif
 
     mTopLeftCornerMask = NULL;
   }
 
   // register for things we'll take from other applications
   [ChildView registerViewForDraggedTypes:self];
 
@@ -4088,91 +4092,125 @@ NSEvent* gLastDragMouseDownEvent = nil;
     uint32_t allowedDirectionsCopy = aAllowedDirections;
     [self sendSwipeEvent:anEvent
                 withKind:NS_SIMPLE_GESTURE_SWIPE_END
        allowedDirections:&allowedDirectionsCopy
                direction:0
                    delta:0.0];
 }
 
-// Support fluid swipe tracking on OS X 10.7 and higher.  We must be careful
-// to only invoke this support on a horizontal two-finger gesture that really
+// Support fluid swipe tracking on OS X 10.7 and higher. We must be careful
+// to only invoke this support on a two-finger gesture that really
 // is a swipe (and not a scroll) -- in other words, the app is responsible
-// for deciding which is which.  But once the decision is made, the OS tracks
+// for deciding which is which. But once the decision is made, the OS tracks
 // the swipe until it has finished, and decides whether or not it succeeded.
-// A swipe has the same functionality as the Back and Forward buttons.  For
-// now swipe animation is unsupported (e.g. no bounces).  This method is
-// partly based on Apple sample code available at
-// http://developer.apple.com/library/mac/#releasenotes/Cocoa/AppKit.html
+// A horizontal swipe has the same functionality as the Back and Forward
+// buttons.
+// This method is partly based on Apple sample code available at
+// developer.apple.com/library/mac/#releasenotes/Cocoa/AppKitOlderNotes.html
+// (under Fluid Swipe Tracking API).
 - (void)maybeTrackScrollEventAsSwipe:(NSEvent *)anEvent
-                      scrollOverflow:(double)overflow
+                     scrollOverflowX:(double)anOverflowX
+                     scrollOverflowY:(double)anOverflowY
+              viewPortIsOverscrolled:(BOOL)aViewPortIsOverscrolled
 {
   if (!nsCocoaFeatures::OnLionOrLater()) {
     return;
   }
 
   // This method checks whether the AppleEnableSwipeNavigateWithScrolls global
   // preference is set.  If it isn't, fluid swipe tracking is disabled, and a
   // horizontal two-finger gesture is always a scroll (even in Safari).  This
   // preference can't (currently) be set from the Preferences UI -- only using
   // 'defaults write'.
   if (![NSEvent isSwipeTrackingFromScrollEventsEnabled]) {
     return;
   }
 
+  // We should only track scroll events as swipe if the viewport is being
+  // overscrolled.
+  if (!aViewPortIsOverscrolled) {
+    return;
+  }
+
   // Verify that this is a scroll wheel event with proper phase to be tracked
   // by the OS.
   if ([anEvent type] != NSScrollWheel || [anEvent phase] == NSEventPhaseNone) {
     return;
   }
 
   // Only initiate tracking if the user has tried to scroll past the edge of
-  // the current page (as indicated by 'overflow' being non-zero).  Gecko only
-  // sets WidgetMouseScrollEvent.scrollOverflow when it's processing
-  // NS_MOUSE_PIXEL_SCROLL events (not NS_MOUSE_SCROLL events).
-  // WidgetMouseScrollEvent.scrollOverflow only indicates left or right overflow
-  // for horizontal NS_MOUSE_PIXEL_SCROLL events.
-  if (!overflow) {
+  // the current page (as indicated by 'anOverflowX' or 'anOverflowY' being
+  // non-zero). Gecko only sets WidgetMouseScrollEvent.scrollOverflow when it's
+  // processing NS_MOUSE_PIXEL_SCROLL events (not NS_MOUSE_SCROLL events).
+  if (anOverflowX == 0.0 && anOverflowY == 0.0) {
     return;
   }
 
   CGFloat deltaX, deltaY;
   if ([anEvent hasPreciseScrollingDeltas]) {
     deltaX = [anEvent scrollingDeltaX];
     deltaY = [anEvent scrollingDeltaY];
   } else {
-    deltaX = [anEvent deltaX];
-    deltaY = [anEvent deltaY];
-  }
-
+    return;
+  }
+
+  uint32_t vDirs = (uint32_t)nsIDOMSimpleGestureEvent::DIRECTION_DOWN |
+                   (uint32_t)nsIDOMSimpleGestureEvent::DIRECTION_UP;
   uint32_t direction = 0;
+
   // Only initiate horizontal tracking for events whose horizontal element is
   // at least eight times larger than its vertical element. This minimizes
   // performance problems with vertical scrolls (by minimizing the possibility
   // that they'll be misinterpreted as horizontal swipes), while still
   // tolerating a small vertical element to a true horizontal swipe.  The number
   // '8' was arrived at by trial and error.
-  if (overflow != 0.0 && deltaX != 0.0 &&
+  if (anOverflowX != 0.0 && deltaX != 0.0 &&
       fabsf(deltaX) > fabsf(deltaY) * 8) {
     // Only initiate horizontal tracking for gestures that have just begun --
     // otherwise a scroll to one side of the page can have a swipe tacked on
     // to it.
     if ([anEvent phase] != NSEventPhaseBegan) {
       return;
     }
 
     if (deltaX < 0.0) {
       direction = (uint32_t)nsIDOMSimpleGestureEvent::DIRECTION_RIGHT;
     } else {
       direction = (uint32_t)nsIDOMSimpleGestureEvent::DIRECTION_LEFT;
     }
+  }
+  // Only initiate vertical tracking for events whose vertical element is
+  // at least two times larger than its horizontal element. This minimizes
+  // performance problems. The number '2' was arrived at by trial and error.
+  else if (anOverflowY != 0.0 && deltaY != 0.0 &&
+           fabsf(deltaY) > fabsf(deltaX) * 2) {
+    if (deltaY < 0.0) {
+      direction = (uint32_t)nsIDOMSimpleGestureEvent::DIRECTION_DOWN;
+    } else {
+      direction = (uint32_t)nsIDOMSimpleGestureEvent::DIRECTION_UP;
+    }
+
+    if ((mCurrentSwipeDir & vDirs) && (mCurrentSwipeDir != direction)) {
+      // If a swipe is currently being tracked kill it -- it's been interrupted
+      // by another gesture event.
+      if (mCancelSwipeAnimation && *mCancelSwipeAnimation == NO) {
+        *mCancelSwipeAnimation = YES;
+        mCancelSwipeAnimation = nil;
+        [self sendSwipeEndEvent:anEvent allowedDirections:0];
+      }
+      return;
+    }
   } else {
     return;
   }
 
+  // Track the direction we're going in.
+  mCurrentSwipeDir = direction;
+
   // If a swipe is currently being tracked kill it -- it's been interrupted
   // by another gesture event.
   if (mCancelSwipeAnimation && *mCancelSwipeAnimation == NO) {
     *mCancelSwipeAnimation = YES;
     mCancelSwipeAnimation = nil;
   }
 
   uint32_t allowedDirections = 0;
@@ -4184,18 +4222,24 @@ NSEvent* gLastDragMouseDownEvent = nil;
                              allowedDirections:&allowedDirections
                                      direction:direction
                                          delta:0.0];
 
   if (!shouldStartSwipe) {
     return;
   }
 
-  double min = (allowedDirections & nsIDOMSimpleGestureEvent::DIRECTION_RIGHT) ? -1 : 0;
-  double max = (allowedDirections & nsIDOMSimpleGestureEvent::DIRECTION_LEFT) ? 1 : 0;
+  CGFloat min = 0.0;
+  CGFloat max = 0.0;
+  if (!(direction & vDirs)) {
+    min = (allowedDirections & nsIDOMSimpleGestureEvent::DIRECTION_RIGHT) ?
+          -1.0 : 0.0;
+    max = (allowedDirections & nsIDOMSimpleGestureEvent::DIRECTION_LEFT) ?
+          1.0 : 0.0;
+  }
 
   __block BOOL animationCanceled = NO;
   __block BOOL geckoSwipeEventSent = NO;
   // At this point, anEvent is the first scroll wheel event in a two-finger
   // horizontal gesture that we've decided to treat as a swipe.  When we call
   // [NSEvent trackSwipeEventWithOptions:...], the OS interprets all
   // subsequent scroll wheel events that are part of this gesture as a swipe,
   // and stops sending them to us.  The OS calls the trackingHandler "block"
@@ -4223,23 +4267,25 @@ NSEvent* gLastDragMouseDownEvent = nil;
     // destroyed).
     // Checking for gestureAmount == 0.0 also works around bug 770626, which
     // happens when DispatchWindowEvent() triggers a modal dialog, which spins
     // the event loop and confuses the OS. This results in several re-entrant
     // calls to this handler.
     if (animationCanceled || !mGeckoChild || gestureAmount == 0.0) {
       *stop = YES;
       animationCanceled = YES;
-      if (gestureAmount == 0.0) {
+      if (gestureAmount == 0.0 ||
+          ((direction & vDirs) && (direction != mCurrentSwipeDir))) {
         if (mCancelSwipeAnimation)
           *mCancelSwipeAnimation = YES;
         mCancelSwipeAnimation = nil;
         [self sendSwipeEndEvent:anEvent
               allowedDirections:allowedDirectionsCopy];
       }
+      mCurrentSwipeDir = 0;
       return;
     }
 
     // Update animation overlay to match gestureAmount.
     [self sendSwipeEvent:anEvent
                 withKind:NS_SIMPLE_GESTURE_SWIPE_UPDATE
        allowedDirections:&allowedDirectionsCopy
                direction:0.0
@@ -4263,16 +4309,17 @@ NSEvent* gLastDragMouseDownEvent = nil;
                   withKind:NS_SIMPLE_GESTURE_SWIPE
          allowedDirections:&allowedDirectionsCopy
                  direction:directionCopy
                      delta:0.0];
     }
 
     if (isComplete) {
       [self sendSwipeEndEvent:anEvent allowedDirections:allowedDirectionsCopy];
+      mCurrentSwipeDir = 0;
       mCancelSwipeAnimation = nil;
     }
   }];
 
   mCancelSwipeAnimation = &animationCanceled;
 }
 #endif // #ifdef __LP64__
 
@@ -4703,50 +4750,64 @@ NSEvent* gLastDragMouseDownEvent = nil;
 }
 
 static int32_t RoundUp(double aDouble)
 {
   return aDouble < 0 ? static_cast<int32_t>(floor(aDouble)) :
                        static_cast<int32_t>(ceil(aDouble));
 }
 
+- (void)sendWheelStartOrStop:(uint32_t)msg forEvent:(NSEvent *)theEvent
+{
+  WidgetWheelEvent wheelEvent(true, msg, mGeckoChild);
+  [self convertCocoaMouseWheelEvent:theEvent toGeckoEvent:&wheelEvent];
+  mExpectingWheelStop = (msg == NS_WHEEL_START);
+  mGeckoChild->DispatchWindowEvent(wheelEvent);
+}
+
+- (void)sendWheelCondition:(BOOL)condition first:(uint32_t)first second:(uint32_t)second forEvent:(NSEvent *)theEvent
+{
+  if (mExpectingWheelStop == condition) {
+    [self sendWheelStartOrStop:first forEvent:theEvent];
+  }
+  [self sendWheelStartOrStop:second forEvent:theEvent];
+}
+
 - (void)scrollWheel:(NSEvent*)theEvent
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
 
   nsAutoRetainCocoaObject kungFuDeathGrip(self);
 
   ChildViewMouseTracker::MouseScrolled(theEvent);
 
   if ([self maybeRollup:theEvent]) {
     return;
   }
 
   if (!mGeckoChild) {
     return;
   }
 
-  WheelEvent wheelEvent(true, NS_WHEEL_WHEEL, mGeckoChild);
-  [self convertCocoaMouseEvent:theEvent toGeckoEvent:&wheelEvent];
-  wheelEvent.deltaMode =
-    Preferences::GetBool("mousewheel.enable_pixel_scrolling", true) ?
-      nsIDOMWheelEvent::DOM_DELTA_PIXEL : nsIDOMWheelEvent::DOM_DELTA_LINE;
-
-  // Calling deviceDeltaX or deviceDeltaY on theEvent will trigger a Cocoa
-  // assertion and an Objective-C NSInternalInconsistencyException if the
-  // underlying "Carbon" event doesn't contain pixel scrolling information.
-  // For these events, carbonEventKind is kEventMouseWheelMoved instead of
-  // kEventMouseScroll.
-  if (wheelEvent.deltaMode == nsIDOMWheelEvent::DOM_DELTA_PIXEL) {
-    EventRef theCarbonEvent = [theEvent _eventRef];
-    UInt32 carbonEventKind = theCarbonEvent ? ::GetEventKind(theCarbonEvent) : 0;
-    if (carbonEventKind != kEventMouseScroll) {
-      wheelEvent.deltaMode = nsIDOMWheelEvent::DOM_DELTA_LINE;
+  if (nsCocoaFeatures::OnLionOrLater()) {
+    NSEventPhase phase = [theEvent phase];
+    // Fire NS_WHEEL_START/STOP events when 2 fingers touch/release the touchpad.
+    if (phase & NSEventPhaseMayBegin) {
+      [self sendWheelCondition:YES first:NS_WHEEL_STOP second:NS_WHEEL_START forEvent:theEvent];
+      return;
     }
-  }
+
+    if (phase & (NSEventPhaseEnded | NSEventPhaseCancelled)) {
+      [self sendWheelCondition:NO first:NS_WHEEL_START second:NS_WHEEL_STOP forEvent:theEvent];
+      return;
+    }
+  }
+
+  WidgetWheelEvent wheelEvent(true, NS_WHEEL_WHEEL, mGeckoChild);
+  [self convertCocoaMouseWheelEvent:theEvent toGeckoEvent:&wheelEvent];
 
   wheelEvent.lineOrPageDeltaX = RoundUp(-[theEvent deltaX]);
   wheelEvent.lineOrPageDeltaY = RoundUp(-[theEvent deltaY]);
 
   if (wheelEvent.deltaMode == nsIDOMWheelEvent::DOM_DELTA_PIXEL) {
     // Some scrolling devices supports pixel scrolling, e.g. a Macbook
     // touchpad or a Mighty Mouse. On those devices, [theEvent deviceDeltaX/Y]
     // contains the amount of pixels to scroll. Since Lion this has changed 
@@ -4768,35 +4829,46 @@ static int32_t RoundUp(double aDouble)
   //       revert the sign.
   // wheelEvent.deltaZ = [theEvent deltaZ];
 
   if (!wheelEvent.deltaX && !wheelEvent.deltaY && !wheelEvent.deltaZ) {
     // No sense in firing off a Gecko event.
     return;
   }
 
-  wheelEvent.isMomentum = nsCocoaUtils::IsMomentumScrollEvent(theEvent);
-
   NPCocoaEvent cocoaEvent;
   ChildViewMouseTracker::AttachPluginEvent(wheelEvent, self, theEvent,
                                            NPCocoaEventScrollWheel,
                                            &cocoaEvent);
 
-  mGeckoChild->DispatchWindowEvent(wheelEvent);
-  if (!mGeckoChild) {
-    return;
-  }
-
+#ifdef __LP64__
+  // Only dispatch this event if we're not currently tracking a scroll event as
+  // swipe.
+  if (!mCancelSwipeAnimation || *mCancelSwipeAnimation == YES) {
+#endif // #ifdef __LP64__
+    mGeckoChild->DispatchWindowEvent(wheelEvent);
+    if (!mGeckoChild) {
+      return;
+    }
 #ifdef __LP64__
-  // overflowDeltaX tells us when the user has tried to scroll past the edge
-  // of a page to the left or the right (in those cases it's non-zero).
-  if (wheelEvent.deltaMode == nsIDOMWheelEvent::DOM_DELTA_PIXEL &&
-      wheelEvent.deltaX != 0.0) {
+  } else {
+    // Manually set these members here since we didn't dispatch the event.
+    wheelEvent.overflowDeltaX = wheelEvent.deltaX;
+    wheelEvent.overflowDeltaY = wheelEvent.deltaY;
+    wheelEvent.mViewPortIsOverscrolled = true;
+  }
+
+  // overflowDeltaX and overflowDeltaY tell us when the user has tried to
+  // scroll past the edge of a page (in those cases it's non-zero).
+  if ((wheelEvent.deltaMode == nsIDOMWheelEvent::DOM_DELTA_PIXEL) &&
+      (wheelEvent.deltaX != 0.0 || wheelEvent.deltaY != 0.0)) {
     [self maybeTrackScrollEventAsSwipe:theEvent
-                        scrollOverflow:wheelEvent.overflowDeltaX];
+                       scrollOverflowX:wheelEvent.overflowDeltaX
+                       scrollOverflowY:wheelEvent.overflowDeltaY
+                viewPortIsOverscrolled:wheelEvent.mViewPortIsOverscrolled];
   }
 #endif // #ifdef __LP64__
 
   NS_OBJC_END_TRY_ABORT_BLOCK;
 }
 
 -(NSMenu*)menuForEvent:(NSEvent*)theEvent
 {
@@ -4845,16 +4917,39 @@ static int32_t RoundUp(double aDouble)
   if ([superView respondsToSelector:@selector(contextMenu)])
     return [(NSView<mozView>*)superView contextMenu];
 
   return nil;
 
   NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
 }
 
+- (void) convertCocoaMouseWheelEvent:(NSEvent*)aMouseEvent
+                        toGeckoEvent:(WidgetWheelEvent*)outWheelEvent
+{
+  [self convertCocoaMouseEvent:aMouseEvent toGeckoEvent:outWheelEvent];
+  outWheelEvent->deltaMode =
+    Preferences::GetBool("mousewheel.enable_pixel_scrolling", true) ?
+      nsIDOMWheelEvent::DOM_DELTA_PIXEL : nsIDOMWheelEvent::DOM_DELTA_LINE;
+
+  // Calling deviceDeltaX or deviceDeltaY on theEvent will trigger a Cocoa
+  // assertion and an Objective-C NSInternalInconsistencyException if the
+  // underlying "Carbon" event doesn't contain pixel scrolling information.
+  // For these events, carbonEventKind is kEventMouseWheelMoved instead of
+  // kEventMouseScroll.
+  if (outWheelEvent->deltaMode == nsIDOMWheelEvent::DOM_DELTA_PIXEL) {
+    EventRef theCarbonEvent = [aMouseEvent _eventRef];
+    UInt32 carbonEventKind = theCarbonEvent ? ::GetEventKind(theCarbonEvent) : 0;
+    if (carbonEventKind != kEventMouseScroll) {
+      outWheelEvent->deltaMode = nsIDOMWheelEvent::DOM_DELTA_LINE;
+    }
+  }
+  outWheelEvent->isMomentum = nsCocoaUtils::IsMomentumScrollEvent(aMouseEvent);
+}
+
 - (void) convertCocoaMouseEvent:(NSEvent*)aMouseEvent
                    toGeckoEvent:(WidgetInputEvent*)outGeckoEvent
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
 
   NS_ASSERTION(outGeckoEvent, "convertCocoaMouseEvent:toGeckoEvent: requires non-null aoutGeckoEvent");
   if (!outGeckoEvent)
     return;
--- a/widget/cocoa/nsToolkit.mm
+++ b/widget/cocoa/nsToolkit.mm
@@ -285,20 +285,17 @@ nsToolkit* nsToolkit::GetToolkit()
 }
 
 // An alternative to [NSObject poseAsClass:] that isn't deprecated on OS X
 // Leopard and is available to 64-bit binaries on Leopard and above.  Based on
 // ideas and code from http://www.cocoadev.com/index.pl?MethodSwizzling.
 // Since the Method type becomes an opaque type as of Objective-C 2.0, we'll
 // have to switch to using accessor methods like method_exchangeImplementations()
 // when we build 64-bit binaries that use Objective-C 2.0 (on and for Leopard
-// and above).  But these accessor methods aren't available in Objective-C 1
-// (or on Tiger).  So we need to access Method's members directly for (Tiger-
-// capable) binaries (32-bit or 64-bit) that use Objective-C 1 (as long as we
-// keep supporting Tiger).
+// and above).
 //
 // Be aware that, if aClass doesn't have an orgMethod selector but one of its
 // superclasses does, the method substitution will (in effect) take place in
 // that superclass (rather than in aClass itself).  The substitution has
 // effect on the class where it takes place and all of that class's
 // subclasses.  In order for method swizzling to work properly, posedMethod
 // needs to be unique in the class where the substitution takes place and all
 // of its subclasses.
@@ -316,20 +313,14 @@ nsresult nsToolkit::SwizzleMethods(Class
   } else {
     original = class_getInstanceMethod(aClass, orgMethod);
     posed = class_getInstanceMethod(aClass, posedMethod);
   }
 
   if (!original || !posed)
     return NS_ERROR_FAILURE;
 
-#ifdef __LP64__
   method_exchangeImplementations(original, posed);
-#else
-  IMP aMethodImp = original->method_imp;
-  original->method_imp = posed->method_imp;
-  posed->method_imp = aMethodImp;
-#endif
 
   return NS_OK;
 
   NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
 }