Merge inbound to m-c.
authorRyan VanderMeulen <ryanvm@gmail.com>
Tue, 11 Jun 2013 15:01:22 -0400
changeset 146134 0acda90a6f6aac6dc970afaabab158183703d18f
parent 146122 acc83523042859fe4389993f95aab1f5efc68946 (current diff)
parent 146133 22b38f0b80849de065388ef3f418e43a518ce0fa (diff)
child 146135 2912073936087029874748e744c7a55278dc07cf
child 146136 32ea84579cfbe9ee959849f4d8250c3253d88441
child 146173 5fd0dc3b821bbcb8490c93ba585e45e22eaa6063
child 170000 2352cb62c463ece54602a3adf9cad71e1fdce9b8
push id2697
push userbbajaj@mozilla.com
push dateMon, 05 Aug 2013 18:49:53 +0000
treeherdermozilla-beta@dfec938c7b63 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone24.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 inbound to m-c.
--- a/gfx/layers/FrameMetrics.h
+++ b/gfx/layers/FrameMetrics.h
@@ -27,17 +27,16 @@ public:
   typedef uint64_t ViewID;
   static const ViewID NULL_SCROLL_ID;   // This container layer does not scroll.
   static const ViewID ROOT_SCROLL_ID;   // This is the root scroll frame.
   static const ViewID START_SCROLL_ID;  // This is the ID that scrolling subframes
                                         // will begin at.
 
   FrameMetrics()
     : mCompositionBounds(0, 0, 0, 0)
-    , mContentRect(0, 0, 0, 0)
     , mDisplayPort(0, 0, 0, 0)
     , mCriticalDisplayPort(0, 0, 0, 0)
     , mViewport(0, 0, 0, 0)
     , mScrollOffset(0, 0)
     , mScrollId(NULL_SCROLL_ID)
     , mScrollableRect(0, 0, 0, 0)
     , mResolution(1, 1)
     , mZoom(1, 1)
@@ -46,17 +45,16 @@ public:
     , mPresShellId(-1)
   {}
 
   // Default copy ctor and operator= are fine
 
   bool operator==(const FrameMetrics& aOther) const
   {
     return mCompositionBounds.IsEqualEdges(aOther.mCompositionBounds) &&
-           mContentRect.IsEqualEdges(aOther.mContentRect) &&
            mDisplayPort.IsEqualEdges(aOther.mDisplayPort) &&
            mCriticalDisplayPort.IsEqualEdges(aOther.mCriticalDisplayPort) &&
            mViewport.IsEqualEdges(aOther.mViewport) &&
            mScrollOffset == aOther.mScrollOffset &&
            mScrollId == aOther.mScrollId &&
            mScrollableRect.IsEqualEdges(aOther.mScrollableRect) &&
            mResolution == aOther.mResolution &&
            mDevPixelsPerCSSPixel == aOther.mDevPixelsPerCSSPixel &&
@@ -117,27 +115,16 @@ public:
   // or too much of it prerendered. If the displayport is the same as the
   // viewport, there is no need for this and we can just use the viewport
   // instead.
   //
   // This is only valid on the root layer. Nested iframes do not need this
   // metric as they do not have a displayport set. See bug 775452.
   LayerIntRect mCompositionBounds;
 
-  // |mScrollableRect|, stored in layer pixels. DECPRECATED, DO NOT USE.
-  //
-  // This is valid on any layer where |mScrollableRect| is, though it may be
-  // more lazily maintained than |mScrollableRect|. That is, when
-  // |mScrollableRect| is updated, this may lag. For this reason, it's better to
-  // use |mScrollableRect| for any control logic.
-  //
-  // FIXME/bug 785929: Is this really necessary? Can it not be calculated from
-  // |mScrollableRect| whenever it's needed?
-  LayerIntRect mContentRect;
-
   // ---------------------------------------------------------------------------
   // The following metrics are all in CSS pixels. They are not in any uniform
   // space, so each is explained separately.
   //
 
   // The area of a frame's contents that has been painted, relative to the
   // viewport. It is in the same coordinate space as |mViewport|. For example,
   // if it is at 0,0, then it's at the same place at the viewport, which is at
--- a/gfx/layers/composite/AsyncCompositionManager.cpp
+++ b/gfx/layers/composite/AsyncCompositionManager.cpp
@@ -406,25 +406,24 @@ AsyncCompositionManager::TransformScroll
 
   float layerPixelRatioX = 1 / aRootTransform.GetXScale(),
         layerPixelRatioY = 1 / aRootTransform.GetYScale();
 
   LayerIntPoint scrollOffsetLayerPixels = LayerIntPoint::FromCSSPointRounded(
     metrics.mScrollOffset, layerPixelRatioX, layerPixelRatioY);
 
   if (mIsFirstPaint) {
-    mContentRect = metrics.mContentRect;
+    mContentRect = metrics.mScrollableRect;
     SetFirstPaintViewport(scrollOffsetLayerPixels,
                           layerPixelRatioX,
-                          mContentRect,
-                          metrics.mScrollableRect);
+                          mContentRect);
     mIsFirstPaint = false;
-  } else if (!metrics.mContentRect.IsEqualEdges(mContentRect)) {
-    mContentRect = metrics.mContentRect;
-    SetPageRect(metrics.mScrollableRect);
+  } else if (!metrics.mScrollableRect.IsEqualEdges(mContentRect)) {
+    mContentRect = metrics.mScrollableRect;
+    SetPageRect(mContentRect);
   }
 
   // We synchronise the viewport information with Java after sending the above
   // notifications, so that Java can take these into account in its response.
   // Calculate the absolute display port to send to Java
   LayerIntRect displayPort =
     LayerIntRect::FromCSSRectRounded(metrics.mCriticalDisplayPort.IsEmpty()
                                        ? metrics.mDisplayPort
@@ -465,36 +464,37 @@ AsyncCompositionManager::TransformScroll
   treeTransform = gfx3DMatrix(ViewTransform(-scrollCompensation,
                                             gfxSize(scaleX, scaleY)));
 
   // Translate fixed position layers so that they stay in the correct position
   // when scrollOffset and metricsScrollOffset differ.
   gfxPoint fixedOffset;
   gfxSize scaleDiff;
 
+  LayerRect content = LayerRect::FromCSSRect(mContentRect,
+                                             1 / aRootTransform.GetXScale(),
+                                             1 / aRootTransform.GetYScale());
   // If the contents can fit entirely within the widget area on a particular
-  // dimenson, we need to translate and scale so that the fixed layers remain
+  // dimension, we need to translate and scale so that the fixed layers remain
   // within the page boundaries.
-  if (mContentRect.width * tempScaleDiffX < metrics.mCompositionBounds.width) {
+  if (mContentRect.width * scaleX < metrics.mCompositionBounds.width) {
     fixedOffset.x = -metricsScrollOffset.x;
-    scaleDiff.width = std::min(1.0f, metrics.mCompositionBounds.width / (float)mContentRect.width);
+    scaleDiff.width = std::min(1.0f, metrics.mCompositionBounds.width / content.width);
   } else {
-    fixedOffset.x = clamped(scrollOffset.x / tempScaleDiffX, (float)mContentRect.x,
-                       mContentRect.XMost() - metrics.mCompositionBounds.width / tempScaleDiffX) -
-               metricsScrollOffset.x;
+    fixedOffset.x = clamped(scrollOffset.x / tempScaleDiffX, content.x,
+        content.XMost() - metrics.mCompositionBounds.width / tempScaleDiffX) - metricsScrollOffset.x;
     scaleDiff.width = tempScaleDiffX;
   }
 
-  if (mContentRect.height * tempScaleDiffY < metrics.mCompositionBounds.height) {
+  if (mContentRect.height * scaleY < metrics.mCompositionBounds.height) {
     fixedOffset.y = -metricsScrollOffset.y;
-    scaleDiff.height = std::min(1.0f, metrics.mCompositionBounds.height / (float)mContentRect.height);
+    scaleDiff.height = std::min(1.0f, metrics.mCompositionBounds.height / content.height);
   } else {
-    fixedOffset.y = clamped(scrollOffset.y / tempScaleDiffY, (float)mContentRect.y,
-                       mContentRect.YMost() - metrics.mCompositionBounds.height / tempScaleDiffY) -
-               metricsScrollOffset.y;
+    fixedOffset.y = clamped(scrollOffset.y / tempScaleDiffY, content.y,
+        content.YMost() - metrics.mCompositionBounds.height / tempScaleDiffY) - metricsScrollOffset.y;
     scaleDiff.height = tempScaleDiffY;
   }
 
   // The transform already takes the resolution scale into account.  Since we
   // will apply the resolution scale again when computing the effective
   // transform, we must apply the inverse resolution scale here.
   gfx3DMatrix computedTransform = treeTransform * currentTransform;
   computedTransform.Scale(1.0f/container->GetPreXScale(),
@@ -547,21 +547,20 @@ AsyncCompositionManager::TransformShadow
   }
 
   return wantNextFrame;
 }
 
 void
 AsyncCompositionManager::SetFirstPaintViewport(const LayerIntPoint& aOffset,
                                                float aZoom,
-                                               const LayerIntRect& aPageRect,
                                                const CSSRect& aCssPageRect)
 {
 #ifdef MOZ_WIDGET_ANDROID
-  AndroidBridge::Bridge()->SetFirstPaintViewport(aOffset, aZoom, aPageRect, aCssPageRect);
+  AndroidBridge::Bridge()->SetFirstPaintViewport(aOffset, aZoom, aCssPageRect);
 #endif
 }
 
 void
 AsyncCompositionManager::SetPageRect(const CSSRect& aCssPageRect)
 {
 #ifdef MOZ_WIDGET_ANDROID
   AndroidBridge::Bridge()->SetPageRect(aCssPageRect);
--- a/gfx/layers/composite/AsyncCompositionManager.h
+++ b/gfx/layers/composite/AsyncCompositionManager.h
@@ -111,17 +111,16 @@ private:
   // Return true if an AsyncPanZoomController content transform was
   // applied for |aLayer|.  *aWantNextFrame is set to true if the
   // controller wants another animation frame.
   bool ApplyAsyncContentTransformToTree(TimeStamp aCurrentFrame, Layer* aLayer,
                                         bool* aWantNextFrame);
 
   void SetFirstPaintViewport(const LayerIntPoint& aOffset,
                              float aZoom,
-                             const LayerIntRect& aPageRect,
                              const CSSRect& aCssPageRect);
   void SetPageRect(const CSSRect& aCssPageRect);
   void SyncViewportInfo(const LayerIntRect& aDisplayPort,
                         float aDisplayResolution,
                         bool aLayersUpdated,
                         ScreenPoint& aScrollOffset,
                         float& aScaleX, float& aScaleY,
                         gfx::Margin& aFixedLayerMargins,
@@ -158,17 +157,17 @@ private:
   /**
    * Detaches all referents resolved by ResolveRefLayers.
    * Assumes that mLayerManager->GetRoot() and mTargetConfig have not changed
    * since ResolveRefLayers was called.
    */
   void DetachRefLayers();
 
   TargetConfig mTargetConfig;
-  LayerIntRect mContentRect;
+  CSSRect mContentRect;
 
   nsRefPtr<LayerManagerComposite> mLayerManager;
   // When this flag is set, the next composition will be the first for a
   // particular document (i.e. the document displayed on the screen will change).
   // This happens when loading a new page or switching tabs. We notify the
   // front-end (e.g. Java on Android) about this so that it take the new page
   // size and zoom into account when providing us with the next view transform.
   bool mIsFirstPaint;
--- a/gfx/layers/composite/ThebesLayerComposite.cpp
+++ b/gfx/layers/composite/ThebesLayerComposite.cpp
@@ -246,25 +246,27 @@ ThebesLayerComposite::GetCompositionBoun
       // the content resolution.
       Layer* rootLayer = Manager()->GetRoot();
       const gfx3DMatrix& rootTransform = rootLayer->GetTransform();
       float scaleX = rootTransform.GetXScale();
       float scaleY = rootTransform.GetYScale();
 
       // Get the content document bounds, in screen-space.
       const FrameMetrics& metrics = scrollableLayer->GetFrameMetrics();
-      const LayerIntSize& contentSize = metrics.mContentRect.Size();
+      const LayerIntRect content = LayerIntRect::FromCSSRectRounded(metrics.mScrollableRect,
+                                                                    1 / scaleX,
+                                                                    1 / scaleY);
       gfx::Point scrollOffset =
         gfx::Point((metrics.mScrollOffset.x * metrics.LayersPixelsPerCSSPixel().width) / scaleX,
                    (metrics.mScrollOffset.y * metrics.LayersPixelsPerCSSPixel().height) / scaleY);
       const nsIntPoint contentOrigin(
-        metrics.mContentRect.x - NS_lround(scrollOffset.x),
-        metrics.mContentRect.y - NS_lround(scrollOffset.y));
+        content.x - NS_lround(scrollOffset.x),
+        content.y - NS_lround(scrollOffset.y));
       gfxRect contentRect = gfxRect(contentOrigin.x, contentOrigin.y,
-                                    contentSize.width, contentSize.height);
+                                    content.width, content.height);
       gfxRect contentBounds = scrollableLayer->GetEffectiveTransform().
         TransformBounds(contentRect);
 
       // Clip the composition bounds to the content bounds
       compositionBounds.IntersectRect(compositionBounds, contentBounds);
       break;
     }
   }
--- a/gfx/layers/ipc/AsyncPanZoomController.cpp
+++ b/gfx/layers/ipc/AsyncPanZoomController.cpp
@@ -827,40 +827,23 @@ void AsyncPanZoomController::SetComposit
 void AsyncPanZoomController::ScrollBy(const gfx::Point& aOffset) {
   gfx::Point newOffset(mFrameMetrics.mScrollOffset.x + aOffset.x,
                        mFrameMetrics.mScrollOffset.y + aOffset.y);
   FrameMetrics metrics(mFrameMetrics);
   metrics.mScrollOffset = CSSPoint::FromUnknownPoint(newOffset);
   mFrameMetrics = metrics;
 }
 
-void AsyncPanZoomController::SetPageRect(const CSSRect& aCSSPageRect) {
-  FrameMetrics metrics = mFrameMetrics;
-  gfxFloat resolution = CalculateResolution(mFrameMetrics).width;
-
-  // The page rect is the css page rect scaled by the current zoom.
-  // Round the page rect so we don't get any truncation, then get the nsIntRect
-  // from this.
-  metrics.mContentRect = LayerRect::FromCSSRectRoundOut(aCSSPageRect, resolution, resolution);
-  metrics.mScrollableRect = aCSSPageRect;
-
-  mFrameMetrics = metrics;
-}
-
 void AsyncPanZoomController::ScaleWithFocus(float aZoom,
                                             const nsIntPoint& aFocus) {
   float zoomFactor = aZoom / mFrameMetrics.mZoom.width;
   gfxFloat resolution = CalculateResolution(mFrameMetrics).width;
 
   SetZoomAndResolution(aZoom);
 
-  // Force a recalculation of the page rect based on the new zoom and the
-  // current CSS page rect (which is unchanged since it's not affected by zoom).
-  SetPageRect(mFrameMetrics.mScrollableRect);
-
   // If the new scale is very small, we risk multiplying in huge rounding
   // errors, so don't bother adjusting the scroll offset.
   if (resolution >= 0.01f) {
     mFrameMetrics.mScrollOffset.x +=
       gfxFloat(aFocus.x) * (zoomFactor - 1.0) / resolution;
     mFrameMetrics.mScrollOffset.y +=
       gfxFloat(aFocus.y) * (zoomFactor - 1.0) / resolution;
   }
@@ -1267,22 +1250,19 @@ void AsyncPanZoomController::NotifyLayer
   if (aIsFirstPaint || mFrameMetrics.IsDefault()) {
     mPreviousPaintDurations.Clear();
 
     mX.CancelTouch();
     mY.CancelTouch();
 
     mFrameMetrics = aViewportFrame;
 
-    SetPageRect(mFrameMetrics.mScrollableRect);
-
     mState = NOTHING;
   } else if (!mFrameMetrics.mScrollableRect.IsEqualEdges(aViewportFrame.mScrollableRect)) {
     mFrameMetrics.mScrollableRect = aViewportFrame.mScrollableRect;
-    SetPageRect(mFrameMetrics.mScrollableRect);
   }
 
   if (needContentRepaint) {
     RequestContentRepaint();
   }
 }
 
 const FrameMetrics& AsyncPanZoomController::GetFrameMetrics() {
--- a/gfx/layers/ipc/AsyncPanZoomController.h
+++ b/gfx/layers/ipc/AsyncPanZoomController.h
@@ -194,22 +194,16 @@ public:
    */
   void SetCompositorParent(CompositorParent* aCompositorParent);
 
   // --------------------------------------------------------------------------
   // These methods can be called from any thread.
   //
 
   /**
-   * Sets the CSS page rect, and calculates a new page rect based on the zoom
-   * level of the current metrics and the passed in CSS page rect.
-   */
-  void SetPageRect(const CSSRect& aCSSPageRect);
-
-  /**
    * Sets the DPI of the device for use within panning and zooming logic. It is
    * a platform responsibility to set this on initialization of this class and
    * whenever it changes.
    */
   void SetDPI(int aDPI);
 
   /**
    * Gets the DPI of the device for use outside the panning and zooming logic.
--- a/ipc/glue/IPCMessageUtils.h
+++ b/ipc/glue/IPCMessageUtils.h
@@ -1069,34 +1069,32 @@ template <>
 struct ParamTraits<mozilla::layers::FrameMetrics>
 {
   typedef mozilla::layers::FrameMetrics paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
     WriteParam(aMsg, aParam.mScrollableRect);
     WriteParam(aMsg, aParam.mViewport);
-    WriteParam(aMsg, aParam.mContentRect);
     WriteParam(aMsg, aParam.mScrollOffset);
     WriteParam(aMsg, aParam.mDisplayPort);
     WriteParam(aMsg, aParam.mCriticalDisplayPort);
     WriteParam(aMsg, aParam.mCompositionBounds);
     WriteParam(aMsg, aParam.mScrollId);
     WriteParam(aMsg, aParam.mResolution);
     WriteParam(aMsg, aParam.mZoom);
     WriteParam(aMsg, aParam.mDevPixelsPerCSSPixel);
     WriteParam(aMsg, aParam.mMayHaveTouchListeners);
     WriteParam(aMsg, aParam.mPresShellId);
   }
 
   static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
   {
     return (ReadParam(aMsg, aIter, &aResult->mScrollableRect) &&
             ReadParam(aMsg, aIter, &aResult->mViewport) &&
-            ReadParam(aMsg, aIter, &aResult->mContentRect) &&
             ReadParam(aMsg, aIter, &aResult->mScrollOffset) &&
             ReadParam(aMsg, aIter, &aResult->mDisplayPort) &&
             ReadParam(aMsg, aIter, &aResult->mCriticalDisplayPort) &&
             ReadParam(aMsg, aIter, &aResult->mCompositionBounds) &&
             ReadParam(aMsg, aIter, &aResult->mScrollId) &&
             ReadParam(aMsg, aIter, &aResult->mResolution) &&
             ReadParam(aMsg, aIter, &aResult->mZoom) &&
             ReadParam(aMsg, aIter, &aResult->mDevPixelsPerCSSPixel) &&
--- a/js/src/ion/Ion.cpp
+++ b/js/src/ion/Ion.cpp
@@ -1372,17 +1372,17 @@ IonCompile(JSContext *cx, JSScript *scri
     if (!info)
         return AbortReason_Alloc;
 
     BaselineInspector inspector(cx, script);
 
     AutoFlushCache afc("IonCompile");
 
     types::AutoEnterCompilation enterCompiler(cx, CompilerOutputKind(executionMode));
-    if (!enterCompiler.init(script, false, 0))
+    if (!enterCompiler.init(script))
         return AbortReason_Disable;
 
     AutoTempAllocatorRooter root(cx, temp);
 
     IonBuilder *builder = alloc->new_<IonBuilder>(cx, temp, graph, &inspector, info, fp);
     if (!builder)
         return AbortReason_Alloc;
 
--- a/js/src/ion/IonBuilder.cpp
+++ b/js/src/ion/IonBuilder.cpp
@@ -3404,16 +3404,26 @@ IonBuilder::inlineScriptedCall(CallInfo 
 
     // Pop formals again, except leave |fun| on stack for duration of call.
     callInfo.popFormals(current);
     current->push(callInfo.fun());
 
     RootedScript calleeScript(cx, target->nonLazyScript());
     BaselineInspector inspector(cx, target->nonLazyScript());
 
+    // Improve type information of |this| when not set.
+    if (callInfo.constructing() && !callInfo.thisArg()->resultTypeSet()) {
+        types::StackTypeSet *types = types::TypeScript::ThisTypes(calleeScript);
+        MTypeBarrier *barrier = MTypeBarrier::New(callInfo.thisArg(), cloneTypeSet(types), Bailout_Normal);
+        current->add(barrier);
+        MUnbox *unbox = MUnbox::New(barrier, MIRType_Object, MUnbox::Infallible);
+        current->add(unbox);
+        callInfo.setThis(unbox);
+    }
+
     // Start inlining.
     LifoAlloc *alloc = GetIonContext()->temp->lifoAlloc();
     CompileInfo *info = alloc->new_<CompileInfo>(calleeScript.get(), target,
                                                  (jsbytecode *)NULL, callInfo.constructing(),
                                                  this->info().executionMode());
     if (!info)
         return false;
 
--- a/js/src/ion/shared/Lowering-shared-inl.h
+++ b/js/src/ion/shared/Lowering-shared-inl.h
@@ -401,16 +401,18 @@ LIRGeneratorShared::add(T *ins, MInstruc
 static inline uint32_t
 VirtualRegisterOfPayload(MDefinition *mir)
 {
     if (mir->isBox()) {
         MDefinition *inner = mir->toBox()->getOperand(0);
         if (!inner->isConstant() && inner->type() != MIRType_Double)
             return inner->virtualRegister();
     }
+    if (mir->isTypeBarrier())
+        return VirtualRegisterOfPayload(mir->getOperand(0));
     return mir->virtualRegister() + VREG_DATA_OFFSET;
 }
 
 // Note: always call ensureDefined before calling useType/usePayload,
 // so that emitted-at-use operands are handled correctly.
 LUse
 LIRGeneratorShared::useType(MDefinition *mir, LUse::Policy policy)
 {
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -2319,59 +2319,25 @@ StackTypeSet::propertyNeedsBarrier(JSCon
                     return true;
             }
         }
     }
 
     return false;
 }
 
-enum RecompileKind {
-    RECOMPILE_CHECK_MONITORED,
-    RECOMPILE_CHECK_BARRIERS,
-    RECOMPILE_NONE
-};
-
 /*
- * Whether all jitcode for a given pc was compiled with monitoring or barriers.
- * If we reanalyze the script after generating jitcode, new monitoring and
- * barriers will be added which may be duplicating information available when
- * the script was originally compiled, and which should not invalidate that
- * compilation.
- */
-static inline bool
-JITCodeHasCheck(JSScript *script, jsbytecode *pc, RecompileKind kind)
-{
-    if (kind == RECOMPILE_NONE)
-        return false;
-
-    if (script->hasAnyIonScript() ||
-        script->isIonCompilingOffThread() ||
-        script->isParallelIonCompilingOffThread())
-    {
-        return false;
-    }
-
-    return true;
-}
-
-/*
- * Force recompilation of any jitcode for script at pc, or of any other script
+ * Force recompilation of any jitcode for the script, or of any other script
  * which this script was inlined into.
  */
 static inline void
-AddPendingRecompile(JSContext *cx, JSScript *script, jsbytecode *pc,
-                    RecompileKind kind = RECOMPILE_NONE)
-{
-    /*
-     * Trigger recompilation of the script itself, if code was not previously
-     * compiled with the specified information.
-     */
-    if (!JITCodeHasCheck(script, pc, kind))
-        cx->compartment()->types.addPendingRecompile(cx, script, pc);
+AddPendingRecompile(JSContext *cx, JSScript *script)
+{
+    /* Trigger recompilation of the script itself. */
+    cx->compartment()->types.addPendingRecompile(cx, script);
 
     /*
      * Remind Ion not to save the compile code if generating type
      * inference information mid-compilation causes an invalidation of the
      * script being compiled.
      */
     RecompileInfo& info = cx->compartment()->types.compiledInfo;
     if (info.outputIndex != RecompileInfo::NoCompilerRunning) {
@@ -2417,17 +2383,17 @@ class TypeConstraintFreezeStack : public
 
     void newType(JSContext *cx, TypeSet *source, Type type)
     {
         /*
          * Unlike TypeConstraintFreeze, triggering this constraint once does
          * not disable it on future changes to the type set.
          */
         RootedScript script(cx, script_);
-        AddPendingRecompile(cx, script, NULL);
+        AddPendingRecompile(cx, script);
     }
 };
 
 /////////////////////////////////////////////////////////////////////
 // TypeCompartment
 /////////////////////////////////////////////////////////////////////
 
 TypeCompartment::TypeCompartment()
@@ -2788,27 +2754,18 @@ TypeCompartment::processPendingRecompile
 
     /* Steal the list of scripts to recompile, else we will try to recursively recompile them. */
     Vector<RecompileInfo> *pending = pendingRecompiles;
     pendingRecompiles = NULL;
 
     JS_ASSERT(!pending->empty());
 
 #ifdef JS_ION
-    for (unsigned i = 0; i < pending->length(); i++) {
-        CompilerOutput &co = *(*pending)[i].compilerOutput(*this);
-        switch (co.kind()) {
-          case CompilerOutput::Ion:
-          case CompilerOutput::ParallelIon:
-            break;
-        }
-    }
-
     ion::Invalidate(*this, fop, *pending);
-#endif /* JS_ION */
+#endif
 
     fop->delete_(pending);
 }
 
 void
 TypeCompartment::setPendingNukeTypes(JSContext *cx)
 {
     TypeZone *zone = &compartment()->zone()->types;
@@ -2910,17 +2867,17 @@ TypeCompartment::addPendingRecompile(JSC
     }
 
     InferSpew(ISpewOps, "addPendingRecompile: %p:%s:%d", co->script, co->script->filename(), co->script->lineno);
 
     co->setPendingRecompilation();
 }
 
 void
-TypeCompartment::addPendingRecompile(JSContext *cx, JSScript *script, jsbytecode *pc)
+TypeCompartment::addPendingRecompile(JSContext *cx, JSScript *script)
 {
     JS_ASSERT(script);
     if (!constrainedOutputs)
         return;
 
 #ifdef JS_ION
     CancelOffThreadIonCompile(cx->compartment(), script);
 
@@ -2960,17 +2917,17 @@ TypeCompartment::monitorBytecode(JSConte
     if (js_CodeSpec[*pc].format & JOF_INVOKE)
         code.monitoredTypesReturn = true;
 
     if (returnOnly)
         return;
 
     code.monitoredTypes = true;
 
-    AddPendingRecompile(cx, script, pc, RECOMPILE_CHECK_MONITORED);
+    AddPendingRecompile(cx, script);
 }
 
 void
 TypeCompartment::markSetsUnknown(JSContext *cx, TypeObject *target)
 {
     JS_ASSERT(this == &cx->compartment()->types);
     JS_ASSERT(!(target->flags & OBJECT_FLAG_SETS_MARKED_UNKNOWN));
     JS_ASSERT(!target->singleton);
@@ -3048,17 +3005,17 @@ ScriptAnalysis::addTypeBarrier(JSContext
     if (!code.typeBarriers) {
         /*
          * Adding type barriers at a bytecode which did not have them before
          * will trigger recompilation. If there were already type barriers,
          * however, do not trigger recompilation (the script will be recompiled
          * if any of the barriers is ever violated).
          */
         RootedScript script(cx, script_);
-        AddPendingRecompile(cx, script, const_cast<jsbytecode*>(pc), RECOMPILE_CHECK_BARRIERS);
+        AddPendingRecompile(cx, script);
     }
 
     /* Ignore duplicate barriers. */
     size_t barrierCount = 0;
     TypeBarrier *barrier = code.typeBarriers;
     while (barrier) {
         if (barrier->target == target && !barrier->singleton) {
             if (barrier->type == type)
@@ -3107,17 +3064,17 @@ ScriptAnalysis::addSingletonTypeBarrier(
 {
     JS_ASSERT(singletonId == IdToTypeId(singletonId) && !JSID_IS_VOID(singletonId));
 
     Bytecode &code = getCode(pc);
 
     if (!code.typeBarriers) {
         /* Trigger recompilation as for normal type barriers. */
         RootedScript script(cx, script_);
-        AddPendingRecompile(cx, script, const_cast<jsbytecode*>(pc), RECOMPILE_CHECK_BARRIERS);
+        AddPendingRecompile(cx, script);
     }
 
     InferSpew(ISpewOps, "singletonTypeBarrier: #%u:%05u: %sT%p%s %p %s",
               script_->id(), pc - script_->code,
               InferSpewColor(target), target, InferSpewColorReset(),
               (void *) singleton.get(), TypeIdString(singletonId));
 
     TypeBarrier *barrier = cx->analysisLifoAlloc().new_<TypeBarrier>(target, Type::UndefinedType(),
@@ -3158,18 +3115,16 @@ TypeCompartment::print(JSContext *cx, bo
 
     printf("Counts: ");
     for (unsigned count = 0; count < TYPE_COUNT_LIMIT; count++) {
         if (count)
             printf("/");
         printf("%u", typeCounts[count]);
     }
     printf(" (%u over)\n", typeCountOver);
-
-    printf("Recompilations: %u\n", recompilations);
 }
 
 /////////////////////////////////////////////////////////////////////
 // TypeCompartment tables
 /////////////////////////////////////////////////////////////////////
 
 /*
  * The arrayTypeTable and objectTypeTable are per-compartment tables for making
@@ -5544,17 +5499,17 @@ types::MarkIteratorUnknownSlow(JSContext
     result = cx->new_<TypeResult>(UINT32_MAX, Type::UnknownType());
     if (!result) {
         cx->compartment()->types.setPendingNukeTypes(cx);
         return;
     }
     result->next = script->types->dynamicList;
     script->types->dynamicList = result;
 
-    AddPendingRecompile(cx, script, NULL);
+    AddPendingRecompile(cx, script);
 
     if (!script->hasAnalysis() || !script->analysis()->ranInference())
         return;
 
     ScriptAnalysis *analysis = script->analysis();
 
     for (unsigned i = 0; i < script->length; i++) {
         jsbytecode *pc = script->code + i;
@@ -5657,52 +5612,17 @@ types::TypeDynamicResult(JSContext *cx, 
     TypeResult *result = cx->new_<TypeResult>(pc - script->code, type);
     if (!result) {
         cx->compartment()->types.setPendingNukeTypes(cx);
         return;
     }
     result->next = script->types->dynamicList;
     script->types->dynamicList = result;
 
-    /*
-     * New type information normally requires all code in the entire script to
-     * be recompiled, as changes to types can flow through variables etc. into
-     * other chunks in the compiled script.
-     *
-     * We can do better than this, though, when we can prove the new type will
-     * only be visible at certain points in the script. Namely, for arithmetic
-     * operations which might produce doubles and are then passed to an
-     * expression that cancels out integer overflow, i.e.'OP & -1' or 'OP | 0',
-     * the new type will only affect OP and the bitwise operation.
-     *
-     * This can prevent a significant amount of recompilation in scripts which
-     * use these operations extensively, principally autotranslated code.
-     */
-
-    jsbytecode *ignorePC = pc + GetBytecodeLength(pc);
-    if (*ignorePC == JSOP_POP) {
-        /* Value is ignored. */
-    } else if (*ignorePC == JSOP_INT8 && GET_INT8(ignorePC) == -1) {
-        ignorePC += JSOP_INT8_LENGTH;
-        if (*ignorePC != JSOP_BITAND)
-            ignorePC = NULL;
-    } else if (*ignorePC == JSOP_ZERO) {
-        ignorePC += JSOP_ZERO_LENGTH;
-        if (*ignorePC != JSOP_BITOR)
-            ignorePC = NULL;
-    } else {
-        ignorePC = NULL;
-    }
-
-    if (ignorePC) {
-        AddPendingRecompile(cx, script, pc);
-        AddPendingRecompile(cx, script, ignorePC);
-    } else {
-        AddPendingRecompile(cx, script, NULL);
-    }
+    AddPendingRecompile(cx, script);
 
     if (script->hasAnalysis() && script->analysis()->ranInference()) {
         TypeSet *pushed = script->analysis()->pushedTypes(pc, 0);
         pushed->addType(cx, type);
     }
 }
 
 void
--- a/js/src/jsinfer.h
+++ b/js/src/jsinfer.h
@@ -1286,20 +1286,17 @@ struct CompilerOutput
     };
 
     JSScript *script;
 
     // This integer will always be a member of CompilerOutput::Kind,
     // but, for portability, bitfields are limited to bool, int, and
     // unsigned int.  You should really use the accessor below.
     unsigned kindInt : 2;
-    bool constructing : 1;
-    bool barriers : 1;
     bool pendingRecompilation : 1;
-    uint32_t chunkIndex:27;
 
     CompilerOutput();
 
     Kind kind() const { return static_cast<Kind>(kindInt); }
     void setKind(Kind k) { kindInt = k; }
 
     ion::IonScript *ion() const;
 
@@ -1360,24 +1357,16 @@ struct TypeCompartment
 
     /* Valid & Invalid script referenced by type constraints. */
     Vector<CompilerOutput> *constrainedOutputs;
 
     /* Pending recompilations to perform before execution of JIT code can resume. */
     Vector<RecompileInfo> *pendingRecompiles;
 
     /*
-     * Number of recompilation events and inline frame expansions that have
-     * occurred in this compartment. If these change, code should not count on
-     * compiled code or the current stack being intact.
-     */
-    unsigned recompilations;
-    unsigned frameExpansions;
-
-    /*
      * Script currently being compiled. All constraints which look for type
      * changes inducing recompilation are keyed to this script. Note: script
      * compilation is not reentrant.
      */
     RecompileInfo compiledInfo;
 
     /* Table for referencing types of objects keyed to an allocation site. */
     AllocationSiteTable *allocationSiteTable;
@@ -1428,17 +1417,17 @@ struct TypeCompartment
 
     void processPendingRecompiles(FreeOp *fop);
 
     /* Mark all types as needing destruction once inference has 'finished'. */
     void setPendingNukeTypes(JSContext *cx);
 
     /* Mark a script as needing recompilation once inference has finished. */
     void addPendingRecompile(JSContext *cx, const RecompileInfo &info);
-    void addPendingRecompile(JSContext *cx, JSScript *script, jsbytecode *pc);
+    void addPendingRecompile(JSContext *cx, JSScript *script);
 
     /* Monitor future effects on a bytecode. */
     void monitorBytecode(JSContext *cx, JSScript *script, uint32_t offset,
                          bool returnOnly = false);
 
     /* Mark any type set containing obj as having a generic object type. */
     void markSetsUnknown(JSContext *cx, TypeObject *obj);
 
--- a/js/src/jsinferinlines.h
+++ b/js/src/jsinferinlines.h
@@ -87,20 +87,17 @@ namespace types {
 
 /////////////////////////////////////////////////////////////////////
 // CompilerOutput & RecompileInfo
 /////////////////////////////////////////////////////////////////////
 
 inline
 CompilerOutput::CompilerOutput()
   : script(NULL),
-    kindInt(Ion),
-    constructing(false),
-    barriers(false),
-    chunkIndex(false)
+    kindInt(Ion)
 {
 }
 
 inline ion::IonScript *
 CompilerOutput::ion() const
 {
 #ifdef JS_ION
     JS_ASSERT(isValid());
@@ -389,24 +386,21 @@ struct AutoEnterCompilation
       : cx(cx),
         info(cx->compartment()->types.compiledInfo),
         kind(kind)
     {
         JS_ASSERT(cx->compartment()->activeAnalysis);
         JS_ASSERT(info.outputIndex == RecompileInfo::NoCompilerRunning);
     }
 
-    bool init(JSScript *script, bool constructing, unsigned chunkIndex)
+    bool init(JSScript *script)
     {
         CompilerOutput co;
         co.script = script;
         co.setKind(kind);
-        co.constructing = constructing;
-        co.barriers = cx->zone()->compileBarriers();
-        co.chunkIndex = chunkIndex;
 
         // This flag is used to prevent adding the current compiled script in
         // the list of compiler output which should be invalided.  This is
         // necessary because we can run some analysis might discard the script
         // it-self, which can happen when the monitored value does not reflect
         // the types propagated by the type inference.
         co.pendingRecompilation = true;
 
--- a/js/src/vm/ForkJoin.cpp
+++ b/js/src/vm/ForkJoin.cpp
@@ -931,16 +931,20 @@ BailoutExplanation(ParallelBailoutCause 
       case ParallelBailoutOutOfMemory:
         return "out of memory";
       case ParallelBailoutUnsupported:
         return "unsupported";
       case ParallelBailoutUnsupportedStringComparison:
         return "unsupported string comparison";
       case ParallelBailoutUnsupportedSparseArray:
         return "unsupported sparse array";
+      case ParallelBailoutRequestedGC:
+        return "requested GC";
+      case ParallelBailoutRequestedZoneGC:
+        return "requested zone GC";
       default:
         return "no known reason";
     }
 }
 
 void
 js::ParallelDo::determineBailoutCause()
 {
@@ -1440,16 +1444,18 @@ ForkJoinShared::check(ForkJoinSlice &sli
             // requestZoneGC() methods should be invoked.
             JS_ASSERT(!cx_->runtime()->gcIsNeeded);
 
             // If interrupt is requested, bring worker threads to a halt,
             // service the interrupt, then let them start back up again.
             // AutoRendezvous autoRendezvous(slice);
             // if (!js_HandleExecutionInterrupt(cx_))
             //     return setAbortFlag(true);
+            slice.bailoutRecord->setCause(ParallelBailoutInterrupt,
+                                          NULL, NULL, NULL);
             setAbortFlag(false);
             return false;
         }
     } else if (rendezvous_) {
         joinRendezvous(slice);
     }
 
     return true;
@@ -1636,23 +1642,27 @@ ForkJoinSlice::InitializeTLS()
     }
     return true;
 }
 
 void
 ForkJoinSlice::requestGC(JS::gcreason::Reason reason)
 {
     shared->requestGC(reason);
+    bailoutRecord->setCause(ParallelBailoutRequestedGC,
+                            NULL, NULL, NULL);
     shared->setAbortFlag(false);
 }
 
 void
 ForkJoinSlice::requestZoneGC(JS::Zone *zone, JS::gcreason::Reason reason)
 {
     shared->requestZoneGC(zone, reason);
+    bailoutRecord->setCause(ParallelBailoutRequestedZoneGC,
+                            NULL, NULL, NULL);
     shared->setAbortFlag(false);
 }
 
 /////////////////////////////////////////////////////////////////////////////
 
 uint32_t
 js::ForkJoinSlices(JSContext *cx)
 {
--- a/js/src/vm/ForkJoin.h
+++ b/js/src/vm/ForkJoin.h
@@ -253,16 +253,18 @@ enum ParallelBailoutCause {
     ParallelBailoutCalledToUncompiledScript,
     ParallelBailoutIllegalWrite,
     ParallelBailoutAccessToIntrinsic,
     ParallelBailoutOverRecursed,
     ParallelBailoutOutOfMemory,
     ParallelBailoutUnsupported,
     ParallelBailoutUnsupportedStringComparison,
     ParallelBailoutUnsupportedSparseArray,
+    ParallelBailoutRequestedGC,
+    ParallelBailoutRequestedZoneGC,
 };
 
 struct ParallelBailoutTrace {
     JSScript *script;
     jsbytecode *bytecode;
 };
 
 // See "Bailouts" section in comment above.
--- a/js/xpconnect/src/XPCWrappedJSClass.cpp
+++ b/js/xpconnect/src/XPCWrappedJSClass.cpp
@@ -1007,16 +1007,21 @@ nsXPCWrappedJSClass::CheckForException(X
                 // exceptional and shouldn't be reported. We have to do this
                 // check here instead of in xpcwrappedjs (like we do for QI) to
                 // avoid adding extra code to all xpcwrappedjs objects.
                 if (reportable && e_result == NS_ERROR_NO_INTERFACE &&
                     !strcmp(anInterfaceName, "nsIInterfaceRequestor") &&
                     !strcmp(aPropertyName, "getInterface")) {
                     reportable = false;
                 }
+
+                // More special case, see bug 877760.
+                if (e_result == NS_ERROR_XPC_JSOBJECT_HAS_NO_FUNCTION_NAMED) {
+                    reportable = false;
+                }
             }
 
             // Try to use the error reporter set on the context to handle this
             // error if it came from a JS exception.
             if (reportable && is_js_exception &&
                 JS_GetErrorReporter(cx) != xpcWrappedJSErrorReporter) {
                 reportable = !JS_ReportPendingException(cx);
             }
--- a/layout/base/Units.h
+++ b/layout/base/Units.h
@@ -78,22 +78,16 @@ struct LayerPixel {
                                       aRect.width * aResolutionX,
                                       aRect.height * aResolutionY);
   }
 
   static gfx::IntRectTyped<LayerPixel> FromCSSRectRounded(const CSSRect& aRect, float aResolutionX, float aResolutionY) {
     return RoundToInt(FromCSSRect(aRect, aResolutionX, aResolutionY));
   }
 
-  static gfx::IntRectTyped<LayerPixel> FromCSSRectRoundOut(const CSSRect& aRect, float aResolutionX, float aResolutionY) {
-    gfx::RectTyped<LayerPixel> scaled(aRect.x, aRect.y, aRect.width, aRect.height);
-    scaled.ScaleInverseRoundOut(aResolutionX, aResolutionY);
-    return gfx::IntRectTyped<LayerPixel>(scaled.x, scaled.y, scaled.width, scaled.height);
-  }
-
   static CSSIntRect ToCSSIntRectRoundIn(const gfx::IntRectTyped<LayerPixel>& aRect, float aResolutionX, float aResolutionY) {
     gfx::IntRectTyped<CSSPixel> ret(aRect.x, aRect.y, aRect.width, aRect.height);
     ret.ScaleInverseRoundIn(aResolutionX, aResolutionY);
     return ret;
   }
 };
 
 typedef gfx::PointTyped<LayerPixel> LayerPoint;
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -647,32 +647,22 @@ static void RecordFrameMetrics(nsIFrame*
   if (aScrollFrame)
     scrollableFrame = aScrollFrame->GetScrollTargetFrame();
 
   if (scrollableFrame) {
     nsRect contentBounds = scrollableFrame->GetScrollRange();
     contentBounds.width += scrollableFrame->GetScrollPortRect().width;
     contentBounds.height += scrollableFrame->GetScrollPortRect().height;
     metrics.mScrollableRect = CSSRect::FromAppUnits(contentBounds);
-    nsIntRect contentRect = contentBounds.ScaleToNearestPixels(
-      aContainerParameters.mXScale, aContainerParameters.mYScale, auPerDevPixel);
-    // I'm not sure what units contentRect is really in, hence FromUnknownRect
-    metrics.mContentRect = LayerIntRect::FromUnknownRect(mozilla::gfx::IntRect(
-      contentRect.x, contentRect.y, contentRect.width, contentRect.height));
     nsPoint scrollPosition = scrollableFrame->GetScrollPosition();
     metrics.mScrollOffset = CSSPoint::FromAppUnits(scrollPosition);
   }
   else {
     nsRect contentBounds = aForFrame->GetRect();
     metrics.mScrollableRect = CSSRect::FromAppUnits(contentBounds);
-    nsIntRect contentRect = contentBounds.ScaleToNearestPixels(
-      aContainerParameters.mXScale, aContainerParameters.mYScale, auPerDevPixel);
-    // I'm not sure what units contentRect is really in, hence FromUnknownRect
-    metrics.mContentRect = LayerIntRect::FromUnknownRect(mozilla::gfx::IntRect(
-      contentRect.x, contentRect.y, contentRect.width, contentRect.height));
   }
 
   metrics.mScrollId = aScrollId;
 
   nsIPresShell* presShell = presContext->GetPresShell();
   if (TabChild *tc = GetTabChildFrom(presShell)) {
     metrics.mZoom = tc->GetZoom();
   }
--- a/layout/ipc/RenderFrameParent.cpp
+++ b/layout/ipc/RenderFrameParent.cpp
@@ -411,18 +411,18 @@ BuildViewMap(ViewMap& oldContentViews, V
 
     // I don't know what units mViewportSize is in, hence use ToUnknownRect
     // here to mark the current frontier in type info propagation
     gfx::Rect viewport = metrics.mViewport.ToUnknownRect();
     view->mViewportSize = nsSize(
       NSIntPixelsToAppUnits(viewport.width, auPerDevPixel) * aXScale,
       NSIntPixelsToAppUnits(viewport.height, auPerDevPixel) * aYScale);
     view->mContentSize = nsSize(
-      NSIntPixelsToAppUnits(metrics.mContentRect.width, auPerDevPixel) * aXScale,
-      NSIntPixelsToAppUnits(metrics.mContentRect.height, auPerDevPixel) * aYScale);
+      NSFloatPixelsToAppUnits(metrics.mScrollableRect.width, auPerCSSPixel) * aXScale,
+      NSFloatPixelsToAppUnits(metrics.mScrollableRect.height, auPerCSSPixel) * aYScale);
 
     newContentViews[scrollId] = view;
   }
 
   for (Layer* child = aLayer->GetFirstChild();
        child; child = child->GetNextSibling()) {
     BuildViewMap(oldContentViews, newContentViews, aFrameLoader, child,
                  aXScale, aYScale, aAccConfigXScale, aAccConfigYScale);
--- a/layout/xul/base/src/nsSliderFrame.cpp
+++ b/layout/xul/base/src/nsSliderFrame.cpp
@@ -488,47 +488,32 @@ nsSliderFrame::HandleEvent(nsPresContext
 
       // set it
       SetCurrentThumbPosition(scrollbar, pos, false, true); // with snapping
     }
     break;
 
     case NS_TOUCH_END:
     case NS_MOUSE_BUTTON_UP:
-      if (aEvent->message == NS_TOUCH_END ||
-          static_cast<nsMouseEvent*>(aEvent)->button == nsMouseEvent::eLeftButton ||
-          (static_cast<nsMouseEvent*>(aEvent)->button == nsMouseEvent::eMiddleButton &&
-           gMiddlePref)) {
+      if (ShouldScrollForEvent(aEvent)) {
         // stop capturing
         AddListener();
         DragThumb(false);
         if (mChange) {
           StopRepeat();
           mChange = 0;
         }
         //we MUST call nsFrame HandleEvent for mouse ups to maintain the selection state and capture state.
         return nsFrame::HandleEvent(aPresContext, aEvent, aEventStatus);
       }
     }
 
     //return nsFrame::HandleEvent(aPresContext, aEvent, aEventStatus);
     return NS_OK;
-  } else if ((aEvent->message == NS_MOUSE_BUTTON_DOWN &&
-              static_cast<nsMouseEvent*>(aEvent)->button ==
-                nsMouseEvent::eLeftButton &&
-#ifdef XP_MACOSX
-              // On Mac the option key inverts the scroll-to-here preference.
-              (static_cast<nsMouseEvent*>(aEvent)->IsAlt() != GetScrollToClick())) ||
-#else
-              (static_cast<nsMouseEvent*>(aEvent)->IsShift() != GetScrollToClick())) ||
-#endif
-             (gMiddlePref && aEvent->message == NS_MOUSE_BUTTON_DOWN &&
-              static_cast<nsMouseEvent*>(aEvent)->button ==
-                nsMouseEvent::eMiddleButton) ||
-             (aEvent->message == NS_TOUCH_START && GetScrollToClick())) {
+  } else if (ShouldScrollToClickForEvent(aEvent)) {
     nsPoint eventPoint;
     if (!GetEventPoint(aEvent, eventPoint)) {
       return NS_OK;
     }
     nscoord pos = isHorizontal ? eventPoint.x : eventPoint.y;
 
     // adjust so that the middle of the thumb is placed under the click
     nsIFrame* thumbFrame = mFrames.FirstChild();
@@ -568,36 +553,32 @@ nsSliderFrame::HandleEvent(nsPresContext
 }
 
 // Helper function to collect the "scroll to click" metric. Beware of
 // caching this, users expect to be able to change the system preference
 // and see the browser change its behavior immediately.
 bool
 nsSliderFrame::GetScrollToClick()
 {
-  // if there is no parent scrollbar, check the movetoclick attribute. If set
-  // to true, always scroll to the click point. If false, never do this.
-  // Otherwise, the default is true on Mac and false on other platforms.
-  if (GetScrollbar() == this)
+  if (GetScrollbar() != this) {
+    return LookAndFeel::GetInt(LookAndFeel::eIntID_ScrollToClick, false);
+  }
+
+  if (mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::movetoclick,
+                            nsGkAtoms::_true, eCaseMatters)) {
+    return true;
+  }
+  if (mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::movetoclick,
+                            nsGkAtoms::_false, eCaseMatters)) {
+    return false;
+  }
+
 #ifdef XP_MACOSX
-    return !mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::movetoclick,
-                                   nsGkAtoms::_false, eCaseMatters);
- 
-  // if there was no scrollbar, always scroll on click
-  bool scrollToClick = false;
-  int32_t scrollToClickMetric;
-  nsresult rv = LookAndFeel::GetInt(LookAndFeel::eIntID_ScrollToClick,
-                                    &scrollToClickMetric);
-  if (NS_SUCCEEDED(rv) && scrollToClickMetric == 1)
-    scrollToClick = true;
-  return scrollToClick;
-
+  return true;
 #else
-    return mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::movetoclick,
-                                  nsGkAtoms::_true, eCaseMatters);
   return false;
 #endif
 }
 
 nsIFrame*
 nsSliderFrame::GetScrollbar()
 {
   // if we are in a scrollbar then return the scrollbar's content node
@@ -837,47 +818,34 @@ nsSliderFrame::StartDrag(nsIDOMEvent* aE
 {
 #ifdef DEBUG_SLIDER
   printf("Begin dragging\n");
 #endif
   if (mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::disabled,
                             nsGkAtoms::_true, eCaseMatters))
     return NS_OK;
 
-  bool isHorizontal = IsHorizontal();
-  bool scrollToClick = false;
+  nsGUIEvent *event = static_cast<nsGUIEvent*>(aEvent->GetInternalNSEvent());
 
-  nsCOMPtr<nsIDOMMouseEvent> mouseEvent(do_QueryInterface(aEvent));
-  if (mouseEvent) {
-    uint16_t button = 0;
-    mouseEvent->GetButton(&button);
-    if (!(button == 0 || (button == 1 && gMiddlePref)))
-      return NS_OK;
-  
-#ifndef XP_MACOSX
-    // On Mac there's no scroll-to-here when clicking the thumb
-    mouseEvent->GetShiftKey(&scrollToClick);
-    if (button != 0) {
-      scrollToClick = true;
-    }
-#endif
+  if (!ShouldScrollForEvent(event)) {
+    return NS_OK;
   }
 
-  nsGUIEvent *event = static_cast<nsGUIEvent*>(aEvent->GetInternalNSEvent());
-
   nsPoint pt;
   if (!GetEventPoint(event, pt)) {
     return NS_OK;
   }
+  bool isHorizontal = IsHorizontal();
   nscoord pos = isHorizontal ? pt.x : pt.y;
 
-  // If shift click or middle button, first
-  // place the middle of the slider thumb under the click
+  // If we should scroll-to-click, first place the middle of the slider thumb
+  // under the mouse.
   nsCOMPtr<nsIContent> scrollbar;
   nscoord newpos = pos;
+  bool scrollToClick = ShouldScrollToClickForEvent(event);
   if (scrollToClick) {
     // adjust so that the middle of the thumb is placed under the click
     nsIFrame* thumbFrame = mFrames.FirstChild();
     if (!thumbFrame) {
       return NS_OK;
     }
     nsSize thumbSize = thumbFrame->GetSize();
     nscoord thumbLength = isHorizontal ? thumbSize.width : thumbSize.height;
@@ -964,34 +932,102 @@ nsSliderFrame::RemoveListener()
   nsIFrame* thumbFrame = mFrames.FirstChild();
   if (!thumbFrame)
     return;
 
   thumbFrame->GetContent()->
     RemoveSystemEventListener(NS_LITERAL_STRING("mousedown"), mMediator, false);
 }
 
+bool
+nsSliderFrame::ShouldScrollForEvent(nsGUIEvent* aEvent)
+{
+  switch (aEvent->message) {
+    case NS_TOUCH_START:
+    case NS_TOUCH_END:
+      return true;
+    case NS_MOUSE_BUTTON_DOWN:
+    case NS_MOUSE_BUTTON_UP: {
+      uint16_t button = static_cast<nsMouseEvent*>(aEvent)->button;
+      return (button == nsMouseEvent::eLeftButton) ||
+             (button == nsMouseEvent::eMiddleButton && gMiddlePref);
+    }
+    default:
+      return false;
+  }
+}
+
+bool
+nsSliderFrame::ShouldScrollToClickForEvent(nsGUIEvent* aEvent)
+{
+  if (!ShouldScrollForEvent(aEvent)) {
+    return false;
+  }
+
+  if (aEvent->message == NS_TOUCH_START) {
+    return GetScrollToClick();
+  }
+
+  if (aEvent->message != NS_MOUSE_BUTTON_DOWN) {
+    return false;
+  }
+
+#ifdef XP_MACOSX
+  // On Mac, clicking the scrollbar thumb should never scroll to click.
+  if (IsEventOverThumb(aEvent)) {
+    return false;
+  }
+#endif
+
+  nsMouseEvent* mouseEvent = static_cast<nsMouseEvent*>(aEvent);
+  if (mouseEvent->button == nsMouseEvent::eLeftButton) {
+#ifdef XP_MACOSX
+    bool invertPref = mouseEvent->IsAlt();
+#else
+    bool invertPref = mouseEvent->IsShift();
+#endif
+    return GetScrollToClick() != invertPref;
+  }
+
+  return true;
+}
+
+bool
+nsSliderFrame::IsEventOverThumb(nsGUIEvent* aEvent)
+{
+  nsIFrame* thumbFrame = mFrames.FirstChild();
+  if (!thumbFrame) {
+    return false;
+  }
+
+  nsPoint eventPoint;
+  if (!GetEventPoint(aEvent, eventPoint)) {
+    return false;
+  }
+
+  bool isHorizontal = IsHorizontal();
+  nsRect thumbRect = thumbFrame->GetRect();
+  nscoord eventPos = isHorizontal ? eventPoint.x : eventPoint.y;
+  nscoord thumbStart = isHorizontal ? thumbRect.x : thumbRect.y;
+  nscoord thumbEnd = isHorizontal ? thumbRect.XMost() : thumbRect.YMost();
+
+  return eventPos >= thumbStart && eventPos < thumbEnd;
+}
+
 NS_IMETHODIMP
 nsSliderFrame::HandlePress(nsPresContext* aPresContext,
                            nsGUIEvent*     aEvent,
                            nsEventStatus*  aEventStatus)
 {
-  if (aEvent->message == NS_TOUCH_START && GetScrollToClick()) {
+  if (!ShouldScrollForEvent(aEvent) || ShouldScrollToClickForEvent(aEvent)) {
     return NS_OK;
   }
 
-  if (aEvent->message == NS_MOUSE_BUTTON_DOWN) {
-#ifdef XP_MACOSX
-    // On Mac the option key inverts the scroll-to-here preference.
-    if (((nsMouseEvent *)aEvent)->IsAlt() != GetScrollToClick()) {
-#else
-    if (((nsMouseEvent *)aEvent)->IsShift() != GetScrollToClick()) {
-#endif
-      return NS_OK;
-    }
+  if (IsEventOverThumb(aEvent)) {
+    return NS_OK;
   }
 
   nsIFrame* thumbFrame = mFrames.FirstChild();
   if (!thumbFrame) // display:none?
     return NS_OK;
 
   if (mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::disabled,
                             nsGkAtoms::_true, eCaseMatters))
--- a/layout/xul/base/src/nsSliderFrame.h
+++ b/layout/xul/base/src/nsSliderFrame.h
@@ -122,16 +122,19 @@ public:
   NS_IMETHOD HandleRelease(nsPresContext* aPresContext,
                            nsGUIEvent *    aEvent,
                            nsEventStatus*  aEventStatus) MOZ_OVERRIDE;
 
 private:
 
   bool GetScrollToClick();
   nsIFrame* GetScrollbar();
+  bool ShouldScrollForEvent(nsGUIEvent* aEvent);
+  bool ShouldScrollToClickForEvent(nsGUIEvent* aEvent);
+  bool IsEventOverThumb(nsGUIEvent* aEvent);
 
   void PageUpDown(nscoord change);
   void SetCurrentThumbPosition(nsIContent* aScrollbar, nscoord aNewPos, bool aIsSmooth,
                                bool aMaySnap);
   void SetCurrentPosition(nsIContent* aScrollbar, int32_t aNewPos, bool aIsSmooth);
   void SetCurrentPositionInternal(nsIContent* aScrollbar, int32_t pos,
                                   bool aIsSmooth);
   void CurrentPositionChanged();
--- a/mobile/android/base/gfx/GeckoLayerClient.java
+++ b/mobile/android/base/gfx/GeckoLayerClient.java
@@ -548,28 +548,27 @@ public class GeckoLayerClient implements
     /** This function is invoked by Gecko via JNI; be careful when modifying signature.
       * The compositor invokes this function just before compositing a frame where the document
       * is different from the document composited on the last frame. In these cases, the viewport
       * information we have in Java is no longer valid and needs to be replaced with the new
       * viewport information provided. setPageRect will never be invoked on the same frame that
       * this function is invoked on; and this function will always be called prior to syncViewportInfo.
       */
     public void setFirstPaintViewport(float offsetX, float offsetY, float zoom,
-            float pageLeft, float pageTop, float pageRight, float pageBottom,
             float cssPageLeft, float cssPageTop, float cssPageRight, float cssPageBottom) {
         synchronized (getLock()) {
             ImmutableViewportMetrics currentMetrics = getViewportMetrics();
 
             Tab tab = Tabs.getInstance().getSelectedTab();
 
+            RectF cssPageRect = new RectF(cssPageLeft, cssPageTop, cssPageRight, cssPageBottom);
             final ImmutableViewportMetrics newMetrics = currentMetrics
                 .setViewportOrigin(offsetX, offsetY)
                 .setZoomFactor(zoom)
-                .setPageRect(new RectF(pageLeft, pageTop, pageRight, pageBottom),
-                             new RectF(cssPageLeft, cssPageTop, cssPageRight, cssPageBottom))
+                .setPageRect(RectUtils.scale(cssPageRect, zoom), cssPageRect)
                 .setIsRTL(tab.getIsRTL());
             // Since we have switched to displaying a different document, we need to update any
             // viewport-related state we have lying around. This includes mGeckoViewport and
             // mViewportMetrics. Usually this information is updated via handleViewportMessage
             // while we remain on the same document.
             post(new Runnable() {
                 @Override
                 public void run() {
@@ -685,19 +684,18 @@ public class GeckoLayerClient implements
 
     /* Invoked by JNI from the compositor thread */
     public ViewTransform syncFrameMetrics(float offsetX, float offsetY, float zoom,
                 float cssPageLeft, float cssPageTop, float cssPageRight, float cssPageBottom,
                 boolean layersUpdated, int x, int y, int width, int height, float resolution,
                 boolean isFirstPaint)
     {
         if (isFirstPaint) {
-            RectF pageRect = RectUtils.scale(new RectF(cssPageLeft, cssPageTop, cssPageRight, cssPageBottom), zoom);
-            setFirstPaintViewport(offsetX, offsetY, zoom, pageRect.left, pageRect.top, pageRect.right,
-                    pageRect.bottom, cssPageLeft, cssPageTop, cssPageRight, cssPageBottom);
+            setFirstPaintViewport(offsetX, offsetY, zoom,
+                                  cssPageLeft, cssPageTop, cssPageRight, cssPageBottom);
         }
 
         return syncViewportInfo(x, y, width, height, resolution, layersUpdated);
     }
 
     /** This function is invoked by Gecko via JNI; be careful when modifying signature. */
     public LayerRenderer.Frame createFrame() {
         // Create the shaders and textures if necessary.
--- a/mobile/android/base/tests/testMasterPassword.java.in
+++ b/mobile/android/base/tests/testMasterPassword.java.in
@@ -25,22 +25,22 @@ public class testMasterPassword extends 
         disableMasterPassword(password, badPassword);
     }
 
     public void enableMasterPassword(String password, String badPassword) {
 
         // Look for the 'Settings' menu if this device/OS uses it
         selectMenuItem("Settings");
         if (dev.type.equals("tablet")) {
-            mSolo.waitForText("Privacy & Security");
+            waitForText("Privacy & Security");
             mSolo.clickOnText("Privacy & Security");
         }
-        mSolo.waitForText("^Use master password$");
+        waitForText("^Use master password$");
         mSolo.clickOnText("^Use master password$");
-        mSolo.waitForText("^Create Master Password$");
+        waitForText("^Create Master Password$");
 
         // Verify that the OK button is not activated until both fields are filled
         closeTabletKeyboard();
         mAsserter.ok(!mSolo.getButton("OK").isEnabled(), "Verify if the OK button is inactive", "The OK button is inactive until both fields are filled");
 
         // Verify that the OK button is not activated until the Confirm password field is filled
         editPasswordField(0, password);
         mAsserter.ok(!mSolo.getButton("OK").isEnabled(), "Verify if the OK button is inactive", "The OK button is inactive until the Confirm password field is filled");
@@ -54,53 +54,52 @@ public class testMasterPassword extends 
         mAsserter.ok(!mSolo.getButton("OK").isEnabled(), "Verify if the OK button is inactive", "The OK button is inactive until the Password field is filled");
 
         // Check that the Master Password is not set when canceling the action
         mSolo.clickOnEditText(0);
         mActions.sendKeys(password);
         mSolo.clearEditText(1);
         mSolo.clickOnEditText(1);
         mActions.sendKeys(password);
-        mSolo.waitForText("^Cancel$");
+        waitForText("^Cancel$");
         mSolo.clickOnText("^Cancel$");
-        mSolo.waitForText("^Use master password$");
+        waitForText("^Use master password$");
         mSolo.clickOnText("^Use master password$");
         mAsserter.ok(mSolo.waitForText("^Create Master Password$"), "Checking if no password was set if the action was canceled", "No password was set");
 
         // Enable Master Password
         mSolo.clickOnEditText(0);
         mActions.sendKeys(password);
         mSolo.clickOnEditText(1);
         mActions.sendKeys(password);
 
         // Verify that the input characters are converted to dots automatically
-        mAsserter.ok(mSolo.waitForText("."), "waiting to convert the letters in dots", "The letters are converted in dots");
+        mAsserter.ok(waitForText("."), "waiting to convert the letters in dots", "The letters are converted in dots");
         mSolo.clickOnButton("OK");
 
         // Verify that the Master Password was set
-        mSolo.waitForText("^Use master password$");
+        waitForText("^Use master password$");
         mSolo.clickOnText("^Use master password$");
         mAsserter.ok(mSolo.searchText("Remove Master Password"), "Checking if the password is enabled", "The password is enabled");
-        closeTabletKeyboard();
-        mActions.sendSpecialKey(Actions.SpecialKey.BACK); // Go back to settings menu
-        mSolo.waitForText("^Settings$");
+        clickOnButton("Cancel"); // Go back to settings menu
+        waitForText("^Settings$");
         mActions.sendSpecialKey(Actions.SpecialKey.BACK);// Close the Settings Menu
     }
 
     public void disableMasterPassword(String password, String badPassword) {
 
         // Look for the 'Settings' menu if this device/OS uses it
         selectMenuItem("Settings");
         if (dev.type.equals("tablet")) {
-            mSolo.waitForText("Privacy & Security");
+            waitForText("Privacy & Security");
             mSolo.clickOnText("Privacy & Security");
         }
-        mSolo.waitForText("^Use master password$");
+        waitForText("^Use master password$");
         mSolo.clickOnText("^Use master password$");
-        mSolo.waitForText("^Remove Master Password$");
+        waitForText("^Remove Master Password$");
 
         // Verify that the OK button is not activated if the password field is empty
         closeTabletKeyboard();
         mAsserter.ok(!mSolo.getButton("OK").isEnabled(), "Verify if the OK button is inactive", "The OK button is inactive if the password field is empty");
 
         // Verify that the OK button is activated if the password field contains characters
         editPasswordField(0, badPassword);
         mAsserter.ok(mSolo.getButton("OK").isEnabled(), "Verify if the OK button is activated", "The OK button is activated even if the wrong password is filled");
@@ -110,33 +109,32 @@ public class testMasterPassword extends 
         // Disable Master Password
         mSolo.clickOnText("^Use master password$");
         mSolo.waitForText("^Remove Master Password$");
         closeTabletKeyboard();
         editPasswordField(0, password);
         mSolo.clickOnButton("OK");
 
         // Verify that the Master Password was disabled
-        mSolo.waitForText("^Use master password$");
+        waitForText("^Use master password$");
         mSolo.clickOnText("^Use master password$");
-        mAsserter.ok(mSolo.waitForText("^Create Master Password$"), "Checking if the password is disabled", "The password is disabled");
-        toggleVKB(); // Close the VKB
-        mActions.sendSpecialKey(Actions.SpecialKey.BACK); // Close the Master Password menu
+        mAsserter.ok(waitForText("^Create Master Password$"), "Checking if the password is disabled", "The password is disabled");
+        clickOnButton("Cancel"); // Go back to settings menu
     }
 
     public void editPasswordField(int i, String password) {
         mSolo.clickOnEditText(i);
         mActions.sendKeys(password);
         mActions.sendSpecialKey(Actions.SpecialKey.BACK); // Close the VKB
     }
 
     public void noDoorhangerDisplayed(String LOGIN_URL) {
         mSolo.waitForText("Browser Blank Page 01 | Enter Search or Address");
         loadUrl(LOGIN_URL);
-        mAsserter.is(mSolo.waitForText("Save password for"), false, "Doorhanger notification is hidden");
+        mAsserter.is(waitForText("Save password for"), false, "Doorhanger notification is hidden");
     }
 
     public void doorhangerDisplayed(String LOGIN_URL) {
         mSolo.waitForText("Browser Blank Page 01 | Enter Search or Address");
         loadUrl(LOGIN_URL);
         mAsserter.is(mSolo.waitForText("Save password for"), true, "Doorhanger notification is displayed");
     }
 
@@ -148,35 +146,47 @@ public class testMasterPassword extends 
         }
     }
 
     public void clearPrivateData() {
 
         // Look for the 'Settings' menu if this device/OS uses it
         selectMenuItem("Settings");
         if (dev.type.equals("tablet")) {
-            mSolo.waitForText("Privacy & Security");
+            waitForText("Privacy & Security");
             mSolo.clickOnText("Privacy & Security");
         }
 
         // Clear private data
-        mSolo.waitForText("^Clear private data$");
+        waitForText("^Clear private data$");
         mSolo.clickOnText("^Clear private data$");
-        mSolo.waitForText("^Clear data$");
-        mSolo.clickOnText("^Clear data$");
-        mAsserter.ok(mSolo.waitForText("^Private data cleared$"), "Waiting for private data to be cleared", "Private data is cleared");
+        waitForText("Browsing & download history"); // Make sure the Clear private data pop-up is displayed
+        Actions.EventExpecter clearPrivateDataEventExpecter = mActions.expectGeckoEvent("Sanitize:Finished");
+        if (mSolo.searchText("Clear data") && !mSolo.searchText("Cookies")) {
+            mSolo.clickOnText("^Clear data$");
+            clearPrivateDataEventExpecter.blockForEvent();
+        } else { // For some reason the pop-up was not opened
+            if (mSolo.searchText("Cookies")) {
+                mSolo.clickOnText("^Clear private data$");
+                waitForText("Browsing & download history"); // Make sure the Clear private data pop-up is displayed
+                mSolo.clickOnText("^Clear data$");
+                clearPrivateDataEventExpecter.blockForEvent();
+            } else {
+                mAsserter.ok(false, "Something happened and the clear data dialog could not be opened", "Failed to clear data");
+            }
+        }
 
         // Check that the Master Password isn't disabled by clearing private data
-        mSolo.waitForText("^Use master password$");
+        waitForText("^Use master password$");
         mSolo.clickOnText("^Use master password$");
         mAsserter.ok(mSolo.searchText("^Remove Master Password$"), "Checking if the master password was disabled by clearing private data", "The master password is not disabled by clearing private data");
-        closeTabletKeyboard();
-        mActions.sendSpecialKey(Actions.SpecialKey.BACK);// Close the Master Password menu
-        mSolo.waitForText("^Settings$");
+        clickOnButton("Cancel"); // Close the Master Password menu
+        waitForText("^Settings$");
         mActions.sendSpecialKey(Actions.SpecialKey.BACK);// Close the Settings Menu
+        waitForText("Browser Blank Page 01"); // Make sure the Settings Menu has been closed
     }
 
     public void verifyLoginPage(String password, String badPassword) {
         String LOGIN_URL = getAbsoluteUrl("/robocop/robocop_login.html");
         String option [] = {"Save", "Don't save"};
 
         doorhangerDisplayed(LOGIN_URL);// Check that the doorhanger is displayed
         for (String item:option) {
@@ -201,13 +211,13 @@ public class testMasterPassword extends 
                 noDoorhangerDisplayed(LOGIN_URL);// Check that the doorhanger isn't displayed
             }
             else {
                 clearPrivateData();
                 doorhangerDisplayed(LOGIN_URL);// Check that the doorhanger is displayed
                 mSolo.clickOnButton(item);
                 doorhangerDisplayed(LOGIN_URL);// Check that the doorhanger is displayed again
                 mSolo.clickOnButton(item);
-                mSolo.waitForText("Browser Blank Page 01");
+                waitForText("Browser Blank Page 01");
             }
         }
     }
 }
--- a/netwerk/base/src/nsStreamTransportService.cpp
+++ b/netwerk/base/src/nsStreamTransportService.cpp
@@ -425,31 +425,24 @@ nsOutputStreamTransport::IsNonBlocking(b
     *result = false;
     return NS_OK;
 }
 
 //-----------------------------------------------------------------------------
 // nsStreamTransportService
 //-----------------------------------------------------------------------------
 
-bool nsStreamTransportService::sHasBeenShutdown = false;
-
 nsStreamTransportService::~nsStreamTransportService()
 {
     NS_ASSERTION(!mPool, "thread pool wasn't shutdown");
 }
 
 nsresult
 nsStreamTransportService::Init()
 {
-    if (sHasBeenShutdown) {
-      // Prevent any attempt at resurrection
-      // (see bug 845190)
-      return NS_ERROR_NOT_AVAILABLE;
-    }
     mPool = do_CreateInstance(NS_THREADPOOL_CONTRACTID);
     NS_ENSURE_STATE(mPool);
 
     // Configure the pool
     mPool->SetName(NS_LITERAL_CSTRING("StreamTrans"));
     mPool->SetThreadLimit(25);
     mPool->SetIdleThreadLimit(1);
     mPool->SetIdleThreadTimeout(PR_SecondsToInterval(30));
@@ -510,15 +503,15 @@ nsStreamTransportService::CreateOutputTr
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsStreamTransportService::Observe(nsISupports *subject, const char *topic,
                                   const PRUnichar *data)
 {
   NS_ASSERTION(strcmp(topic, "xpcom-shutdown-threads") == 0, "oops");
-  sHasBeenShutdown = true;
+
   if (mPool) {
     mPool->Shutdown();
     mPool = nullptr;
   }
   return NS_OK;
 }
--- a/netwerk/base/src/nsStreamTransportService.h
+++ b/netwerk/base/src/nsStreamTransportService.h
@@ -22,15 +22,9 @@ public:
     nsresult Init();
 
     nsStreamTransportService() {}
 
 private:
     ~nsStreamTransportService();
 
     nsCOMPtr<nsIThreadPool> mPool;
-
-    /**
-     * |true| if we have shutdown once already, in which
-     * case we should reject any attempt to resurrect.
-     */
-    static bool sHasBeenShutdown;
 };
--- a/toolkit/components/osfile/osfile_async_front.jsm
+++ b/toolkit/components/osfile/osfile_async_front.jsm
@@ -106,21 +106,16 @@ let clone = function clone(object, refs 
       result[k] = object[k];
     } else {
       refer(result, k, object);
     }
   }
   return result;
 };
 
-/**
- * A shared constant used to normalize a set of options to nothing.
- */
-const noOptions = {};
-
 let worker = new PromiseWorker(
   "resource://gre/modules/osfile/osfile_async_worker.js", LOG);
 let Scheduler = {
   post: function post(...args) {
     // By convention, the last argument of any message may be an |options| object.
     let methodArgs = args[1];
     let options = methodArgs ? methodArgs[methodArgs.length - 1] : null;
     let promise = worker.post.apply(worker, args);
@@ -308,17 +303,17 @@ File.prototype = {
    * modified by another thread. Using this buffer before the |read|
    * operation has completed is a BAD IDEA.
    * @param {JSON} options
    *
    * @return {promise}
    * @resolves {number} The number of bytes effectively read.
    * @rejects {OS.File.Error}
    */
-  readTo: function readTo(buffer, options = noOptions) {
+  readTo: function readTo(buffer, options = {}) {
     // If |buffer| is a typed array and there is no |bytes| options, we
     // need to extract the |byteLength| now, as it will be lost by
     // communication
     if (isTypedArray(buffer) && (!options || !("bytes" in options))) {
       // Preserve the reference to |outExecutionDuration| option if it is
       // passed.
       options = clone(options, ["outExecutionDuration"]);
       options.bytes = buffer.byteLength;
@@ -346,17 +341,17 @@ File.prototype = {
    * @param {*=} options Optionally, an object that may contain the
    * following fields:
    * - {number} bytes The number of |bytes| to write from the buffer. If
    * unspecified, this is |buffer.byteLength|. Note that |bytes| is required
    * if |buffer| is a C pointer.
    *
    * @return {number} The number of bytes actually written.
    */
-  write: function write(buffer, options = noOptions) {
+  write: function write(buffer, options = {}) {
     // If |buffer| is a typed array and there is no |bytes| options,
     // we need to extract the |byteLength| now, as it will be lost
     // by communication
     if (isTypedArray(buffer) && (!options || !("bytes" in options))) {
       // Preserve the reference to |outExecutionDuration| option if it is
       // passed.
       options = clone(options, ["outExecutionDuration"]);
       options.bytes = buffer.byteLength;
@@ -647,17 +642,17 @@ File.exists = function exists(path) {
  * (typically due to a kernel freeze or a power failure) or if the
  * device is disconnected or removed before the buffer is flushed, the
  * file may be corrupted.
  *
  *
  * @return {promise}
  * @resolves {number} The number of bytes actually written.
  */
-File.writeAtomic = function writeAtomic(path, buffer, options = noOptions) {
+File.writeAtomic = function writeAtomic(path, buffer, options = {}) {
   // Copy |options| to avoid modifying the original object but preserve the
   // reference to |outExecutionDuration| option if it is passed.
   options = clone(options, ["outExecutionDuration"]);
   // As options.tmpPath is a path, we need to encode it as |Type.path| message
   if ("tmpPath" in options) {
     options.tmpPath = Type.path.toMsg(options.tmpPath);
   };
   if (isTypedArray(buffer) && (!("bytes" in options))) {
--- a/toolkit/components/osfile/osfile_shared_front.jsm
+++ b/toolkit/components/osfile/osfile_shared_front.jsm
@@ -11,19 +11,16 @@
 
 if (typeof Components != "undefined") {
   throw new Error("osfile_shared_front.jsm cannot be used from the main thread");
 }
 (function(exports) {
 
 let LOG = exports.OS.Shared.LOG.bind(OS.Shared, "Shared front-end");
 
-const noOptions = {};
-
-
 /**
  * Code shared by implementations of File.
  *
  * @param {*} fd An OS-specific file handle.
  * @constructor
  */
 let AbstractFile = function AbstractFile(fd) {
   this._fd = fd;
@@ -75,17 +72,17 @@ AbstractFile.prototype = {
    * following fields:
    * - {number} bytes The number of |bytes| to write from the buffer. If
    * unspecified, this is |buffer.byteLength|. Note that |bytes| is required
    * if |buffer| is a C pointer.
    *
    * @return {number} The number of bytes actually read, which may be
    * less than |bytes| if the file did not contain that many bytes left.
    */
-  readTo: function readTo(buffer, options = noOptions) {
+  readTo: function readTo(buffer, options = {}) {
     let {ptr, bytes} = AbstractFile.normalizeToPointer(buffer, options.bytes);
     let pos = 0;
     while (pos < bytes) {
       let chunkSize = this._read(ptr, bytes - pos, options);
       if (chunkSize == 0) {
         break;
       }
       pos += chunkSize;
@@ -107,17 +104,17 @@ AbstractFile.prototype = {
    * @param {*=} options Optionally, an object that may contain the
    * following fields:
    * - {number} bytes The number of |bytes| to write from the buffer. If
    * unspecified, this is |buffer.byteLength|. Note that |bytes| is required
    * if |buffer| is a C pointer.
    *
    * @return {number} The number of bytes actually written.
    */
-  write: function write(buffer, options = noOptions) {
+  write: function write(buffer, options = {}) {
 
     let {ptr, bytes} = AbstractFile.normalizeToPointer(buffer, options.bytes);
 
     let pos = 0;
     while (pos < bytes) {
       let chunkSize = this._write(ptr, bytes - pos, options);
       pos += chunkSize;
       ptr = exports.OS.Shared.offsetBy(ptr, chunkSize);
@@ -335,17 +332,17 @@ AbstractFile.read = function read(path, 
  * behavior is slightly less safe: if the system shuts down improperly
  * (typically due to a kernel freeze or a power failure) or if the
  * device is disconnected or removed before the buffer is flushed, the
  * file may be corrupted.
  *
  * @return {number} The number of bytes actually written.
  */
 AbstractFile.writeAtomic =
-     function writeAtomic(path, buffer, options = noOptions) {
+     function writeAtomic(path, buffer, options = {}) {
 
   // Verify that path is defined and of the correct type
   if (typeof path != "string" || path == "") {
     throw new TypeError("File path should be a (non-empty) string");
   }
   let noOverwrite = options.noOverwrite;
   if (noOverwrite && OS.File.exists(path)) {
     throw OS.File.Error.exists("writeAtomic");
--- a/toolkit/components/osfile/osfile_unix_front.jsm
+++ b/toolkit/components/osfile/osfile_unix_front.jsm
@@ -161,20 +161,16 @@
       * to be written.
       *
       * @throws {OS.File.Error} In case of I/O error.
       */
      File.prototype.flush = function flush() {
        throw_on_negative("flush", UnixFile.fsync(this.fd));
      };
 
-
-     // Constant used to normalize options.
-     const noOptions = {};
-
      // The default unix mode for opening (0600)
      const DEFAULT_UNIX_MODE = 384;
 
      /**
       * Open a file
       *
       * @param {string} path The path to the file.
       * @param {*=} mode The opening mode for the file, as
@@ -211,17 +207,17 @@
       * - {number} unixMode If specified, a file creation mode,
       *  as per libc function |open|. If unspecified, files are
       *  created with a default mode of 0600 (file is private to the
       *  user, the user can read and write).
       *
       * @return {File} A file object.
       * @throws {OS.File.Error} If the file could not be opened.
       */
-     File.open = function Unix_open(path, mode, options = noOptions) {
+     File.open = function Unix_open(path, mode, options = {}) {
        let omode = options.unixMode || DEFAULT_UNIX_MODE;
        let flags;
        if (options.unixFlags) {
          flags = options.unixFlags;
        } else {
          mode = OS.Shared.AbstractFile.normalizeOpenMode(mode);
          // Handle read/write
          if (!mode.write) {
@@ -282,17 +278,17 @@
      /**
       * Remove an empty directory.
       *
       * @param {string} path The name of the directory to remove.
       * @param {*=} options Additional options.
       *   - {bool} ignoreAbsent If |true|, do not fail if the
       *     directory does not exist yet.
       */
-     File.removeEmptyDir = function removeEmptyDir(path, options = noOptions) {
+     File.removeEmptyDir = function removeEmptyDir(path, options = {}) {
        let result = UnixFile.rmdir(path);
        if (result == -1) {
          if (options.ignoreAbsent && ctypes.errno == Const.ENOENT) {
            return;
          }
          throw new File.Error("removeEmptyDir");
        }
      };
@@ -311,17 +307,17 @@
       *
       * - {number} unixMode If specified, a file creation mode,
       * as per libc function |mkdir|. If unspecified, dirs are
       * created with a default mode of 0700 (dir is private to
       * the user, the user can read, write and execute).
       * - {bool} ignoreExisting If |true|, do not fail if the
       * directory already exists.
       */
-     File.makeDir = function makeDir(path, options = noOptions) {
+     File.makeDir = function makeDir(path, options = {}) {
        let omode = options.unixMode || DEFAULT_UNIX_MODE_DIR;
        let result = UnixFile.mkdir(path, omode);
        if (result != -1 ||
            options.ignoreExisting && ctypes.errno == OS.Constants.libc.EEXIST) {
         return;
        }
        throw new File.Error("makeDir");
      };
@@ -378,17 +374,17 @@
       * behavior may not be the same across all platforms.
       */
      File.move = null;
 
      if (UnixFile.copyfile) {
        // This implementation uses |copyfile(3)|, from the BSD library.
        // Adding copying of hierarchies and/or attributes is just a flag
        // away.
-       File.copy = function copyfile(sourcePath, destPath, options = noOptions) {
+       File.copy = function copyfile(sourcePath, destPath, options = {}) {
          let flags = Const.COPYFILE_DATA;
          if (options.noOverwrite) {
            flags |= Const.COPYFILE_EXCL;
          }
          throw_on_negative("copy",
            UnixFile.copyfile(sourcePath, destPath, null, flags)
          );
        };
@@ -416,17 +412,17 @@
         * @throws {OS.File.Error} In case of error.
         */
        let pump;
 
        // A buffer used by |pump_userland|
        let pump_buffer = null;
 
        // An implementation of |pump| using |read|/|write|
-       let pump_userland = function pump_userland(source, dest, options = noOptions) {
+       let pump_userland = function pump_userland(source, dest, options = {}) {
          let bufSize = options.bufSize || 4096;
          let nbytes = options.nbytes || Infinity;
          if (!pump_buffer || pump_buffer.length < bufSize) {
            pump_buffer = new (ctypes.ArrayType(ctypes.char))(bufSize);
          }
          let read = source._read.bind(source);
          let write = dest._write.bind(dest);
          // Perform actual copy
@@ -452,17 +448,17 @@
          }
        };
 
        // Fortunately, under Linux, that pumping function can be optimized.
        if (UnixFile.splice) {
          const BUFSIZE = 1 << 17;
 
          // An implementation of |pump| using |splice| (for Linux/Android)
-         pump = function pump_splice(source, dest, options = noOptions) {
+         pump = function pump_splice(source, dest, options = {}) {
            let nbytes = options.nbytes || Infinity;
            let pipe = [];
            throw_on_negative("pump", UnixFile.pipe(pipe));
            let pipe_read = pipe[0];
            let pipe_write = pipe[1];
            let source_fd = source.fd;
            let dest_fd = dest.fd;
            let total_read = 0;
@@ -516,17 +512,17 @@
        } else {
          // Fallback implementation of pump for other Unix platforms.
          pump = pump_userland;
        }
 
        // Implement |copy| using |pump|.
        // This implementation would require some work before being able to
        // copy directories
-       File.copy = function copy(sourcePath, destPath, options = noOptions) {
+       File.copy = function copy(sourcePath, destPath, options = {}) {
          let source, dest;
          let result;
          try {
            source = File.open(sourcePath);
            if (options.noOverwrite) {
              dest = File.open(destPath, {create:true});
            } else {
              dest = File.open(destPath, {trunc:true});
@@ -541,17 +537,17 @@
            }
            throw x;
          }
        };
      } // End of definition of copy
 
      // Implement |move| using |rename| (wherever possible) or |copy|
      // (if files are on distinct devices).
-     File.move = function move(sourcePath, destPath, options = noOptions) {
+     File.move = function move(sourcePath, destPath, options = {}) {
        // An implementation using |rename| whenever possible or
        // |File.pump| when required, for other Unices.
        // It can move directories on one file system, not
        // across file systems
 
        // If necessary, fail if the destination file exists
        if (options.noOverwrite) {
          let fd = UnixFile.open(destPath, Const.O_RDONLY, 0);
@@ -790,17 +786,17 @@
       * @param {*=} options Additional options. In this implementation:
       *
       * - {bool} unixNoFollowingLinks If set and |true|, if |path|
       * represents a symbolic link, the call will return the information
       * of the link itself, rather than that of the target file.
       *
       * @return {File.Information}
       */
-     File.stat = function stat(path, options = noOptions) {
+     File.stat = function stat(path, options = {}) {
        if (options.unixNoFollowingLinks) {
          throw_on_negative("stat", UnixFile.lstat(path, gStatDataPtr));
        } else {
          throw_on_negative("stat", UnixFile.stat(path, gStatDataPtr));
        }
        return new File.Info(gStatData);
      };
 
--- a/toolkit/components/osfile/osfile_win_front.jsm
+++ b/toolkit/components/osfile/osfile_win_front.jsm
@@ -183,19 +183,16 @@
       * to be written.
       *
       * @throws {OS.File.Error} In case of I/O error.
       */
      File.prototype.flush = function flush() {
        throw_on_zero("flush", WinFile.FlushFileBuffers(this.fd));
      };
 
-     // Constant used to normalize options.
-     const noOptions = {};
-
      // The default sharing mode for opening files: files are not
      // locked against being reopened for reading/writing or against
      // being deleted by the same process or another process.
      // This is consistent with the default Unix policy.
      const DEFAULT_SHARE = Const.FILE_SHARE_READ |
        Const.FILE_SHARE_WRITE | Const.FILE_SHARE_DELETE;
 
      // The default flags for opening files.
@@ -250,17 +247,17 @@
       * - {number} winDisposition If specified, Windows disposition mode,
       * as per Windows function |CreateFile|. This also requires option
       * |winAccess| and this replaces argument |mode|. If unspecified,
       * uses the string |mode|.
       *
       * @return {File} A file object.
       * @throws {OS.File.Error} If the file could not be opened.
       */
-     File.open = function Win_open(path, mode = noOptions, options = noOptions) {
+     File.open = function Win_open(path, mode = {}, options = {}) {
        let share = options.winShare || DEFAULT_SHARE;
        let security = options.winSecurity || null;
        let flags = options.winFlags || DEFAULT_FLAGS;
        let template = options.winTemplate?options.winTemplate._fd:null;
        let access;
        let disposition;
        if ("winAccess" in options && "winDisposition" in options) {
          access = options.winAccess;
@@ -342,17 +339,17 @@
      /**
       * Remove an empty directory.
       *
       * @param {string} path The name of the directory to remove.
       * @param {*=} options Additional options.
       *   - {bool} ignoreAbsent If |true|, do not fail if the
       *     directory does not exist yet.
       */
-     File.removeEmptyDir = function removeEmptyDir(path, options = noOptions) {
+     File.removeEmptyDir = function removeEmptyDir(path, options = {}) {
        let result = WinFile.RemoveDirectory(path);
        if (!result) {
          if (options.ignoreAbsent &&
              ctypes.winLastError == Const.ERROR_FILE_NOT_FOUND) {
            return;
          }
          throw new File.Error("removeEmptyDir");
        }
@@ -367,17 +364,17 @@
       *
       * - {C pointer} winSecurity If specified, security attributes
       * as per winapi function |CreateDirectory|. If unspecified,
       * use the default security descriptor, inherited from the
       * parent directory.
       * - {bool} ignoreExisting If |true|, do not fail if the
       * directory already exists.
       */
-     File.makeDir = function makeDir(path, options = noOptions) {
+     File.makeDir = function makeDir(path, options = {}) {
        let security = options.winSecurity || null;
        let result = WinFile.CreateDirectory(path, security);
        if (result ||
            options.ignoreExisting &&
            ctypes.winLastError == OS.Constants.Win.ERROR_ALREADY_EXISTS) {
         return;
        }
        throw new File.Error("makeDir");
@@ -401,17 +398,17 @@
       * General note: The behavior of this function is defined only when
       * it is called on a single file. If it is called on a directory, the
       * behavior is undefined and may not be the same across all platforms.
       *
       * General note: The behavior of this function with respect to metadata
       * is unspecified. Metadata may or may not be copied with the file. The
       * behavior may not be the same across all platforms.
      */
-     File.copy = function copy(sourcePath, destPath, options = noOptions) {
+     File.copy = function copy(sourcePath, destPath, options = {}) {
        throw_on_zero("copy",
          WinFile.CopyFile(sourcePath, destPath, options.noOverwrite || false)
        );
      };
 
      /**
       * Move a file to a destination.
       *
@@ -433,17 +430,17 @@
       * General note: The behavior of this function is defined only when
       * it is called on a single file. If it is called on a directory, the
       * behavior is undefined and may not be the same across all platforms.
       *
       * General note: The behavior of this function with respect to metadata
       * is unspecified. Metadata may or may not be moved with the file. The
       * behavior may not be the same across all platforms.
       */
-     File.move = function move(sourcePath, destPath, options = noOptions) {
+     File.move = function move(sourcePath, destPath, options = {}) {
        let flags = 0;
        if (!options.noCopy) {
          flags = Const.MOVEFILE_COPY_ALLOWED;
        }
        if (!options.noOverwrite) {
          flags = flags | Const.MOVEFILE_REPLACE_EXISTING;
        }
        throw_on_zero("move",
--- a/toolkit/components/osfile/tests/xpcshell/xpcshell.ini
+++ b/toolkit/components/osfile/tests/xpcshell/xpcshell.ini
@@ -2,8 +2,10 @@
 head =
 tail =
 
 [test_osfile_closed.js]
 [test_path.js]
 [test_osfile_async.js]
 [test_profiledir.js]
 [test_logging.js]
+# bug 845190 - thread pool wasn't shutdown assertions
+skip-if = os == "win" && debug
--- a/toolkit/components/search/tests/xpcshell/xpcshell.ini
+++ b/toolkit/components/search/tests/xpcshell/xpcshell.ini
@@ -1,15 +1,17 @@
 [DEFAULT]
 head = head_search.js
 tail = 
 firefox-appdir = browser
 
 [test_nocache.js]
 [test_645970.js]
+# Bug 845190: Too many intermittent assertions on Linux (ASSERTION: thread pool wasn't shutdown)
+skip-if = debug && os == "linux"
 [test_identifiers.js]
 [test_init_async_multiple.js]
 [test_init_async_multiple_then_sync.js]
 [test_json_cache.js]
 [test_migratedb.js]
 [test_nodb.js]
 [test_nodb_pluschanges.js]
 [test_save_sorted_engines.js]
--- a/widget/android/AndroidBridge.cpp
+++ b/widget/android/AndroidBridge.cpp
@@ -2109,23 +2109,23 @@ AndroidBridge::IsTablet()
     bool ret = env->CallStaticBooleanMethod(mGeckoAppShellClass, jIsTablet);
     if (jniFrame.CheckForException())
         return false;
 
     return ret;
 }
 
 void
-AndroidBridge::SetFirstPaintViewport(const LayerIntPoint& aOffset, float aZoom, const LayerIntRect& aPageRect, const CSSRect& aCssPageRect)
+AndroidBridge::SetFirstPaintViewport(const LayerIntPoint& aOffset, float aZoom, const CSSRect& aCssPageRect)
 {
     AndroidGeckoLayerClient *client = mLayerClient;
     if (!client)
         return;
 
-    client->SetFirstPaintViewport(aOffset, aZoom, aPageRect, aCssPageRect);
+    client->SetFirstPaintViewport(aOffset, aZoom, aCssPageRect);
 }
 
 void
 AndroidBridge::SetPageRect(const CSSRect& aCssPageRect)
 {
     AndroidGeckoLayerClient *client = mLayerClient;
     if (!client)
         return;
--- a/widget/android/AndroidBridge.h
+++ b/widget/android/AndroidBridge.h
@@ -366,17 +366,17 @@ public:
     already_AddRefed<nsIMobileMessageCallback> DequeueSmsRequest(uint32_t aRequestId);
 
     bool IsTablet();
 
     void GetCurrentNetworkInformation(hal::NetworkInformation* aNetworkInfo);
     void EnableNetworkNotifications();
     void DisableNetworkNotifications();
 
-    void SetFirstPaintViewport(const LayerIntPoint& aOffset, float aZoom, const LayerIntRect& aPageRect, const CSSRect& aCssPageRect);
+    void SetFirstPaintViewport(const LayerIntPoint& aOffset, float aZoom, const CSSRect& aCssPageRect);
     void SetPageRect(const CSSRect& aCssPageRect);
     void SyncViewportInfo(const LayerIntRect& aDisplayPort, float aDisplayResolution, bool aLayersUpdated,
                           ScreenPoint& aScrollOffset, float& aScaleX, float& aScaleY,
                           gfx::Margin& aFixedLayerMargins, ScreenPoint& aOffset);
     void SyncFrameMetrics(const gfx::Point& aScrollOffset, float aZoom, const CSSRect& aCssPageRect,
                           bool aLayersUpdated, const CSSRect& aDisplayPort, float aDisplayResolution,
                           bool aIsFirstPaint, gfx::Margin& aFixedLayerMargins, ScreenPoint& aOffset);
 
--- a/widget/android/AndroidJavaWrappers.cpp
+++ b/widget/android/AndroidJavaWrappers.cpp
@@ -346,17 +346,17 @@ AndroidRectF::InitRectFClass(JNIEnv *jEn
 
 void
 AndroidGeckoLayerClient::InitGeckoLayerClientClass(JNIEnv *jEnv)
 {
     initInit();
 
     jGeckoLayerClientClass = getClassGlobalRef("org/mozilla/gecko/gfx/GeckoLayerClient");
 
-    jSetFirstPaintViewport = getMethod("setFirstPaintViewport", "(FFFFFFFFFFF)V");
+    jSetFirstPaintViewport = getMethod("setFirstPaintViewport", "(FFFFFFF)V");
     jSetPageRect = getMethod("setPageRect", "(FFFF)V");
     jSyncViewportInfoMethod = getMethod("syncViewportInfo",
                                         "(IIIIFZ)Lorg/mozilla/gecko/gfx/ViewTransform;");
     jSyncFrameMetricsMethod = getMethod("syncFrameMetrics",
                                         "(FFFFFFFZIIIIFZ)Lorg/mozilla/gecko/gfx/ViewTransform;");
     jCreateFrameMethod = getMethod("createFrame", "()Lorg/mozilla/gecko/gfx/LayerRenderer$Frame;");
     jActivateProgramMethod = getMethod("activateProgram", "()V");
     jDeactivateProgramMethod = getMethod("deactivateProgram", "()V");
@@ -858,26 +858,25 @@ AndroidViewTransform::Init(jobject jobj)
 void
 AndroidProgressiveUpdateData::Init(jobject jobj)
 {
     NS_ABORT_IF_FALSE(wrapped_obj == nullptr, "Init called on non-null wrapped_obj!");
     wrapped_obj = jobj;
 }
 
 void
-AndroidGeckoLayerClient::SetFirstPaintViewport(const LayerIntPoint& aOffset, float aZoom, const LayerIntRect& aPageRect, const CSSRect& aCssPageRect)
+AndroidGeckoLayerClient::SetFirstPaintViewport(const LayerIntPoint& aOffset, float aZoom, const CSSRect& aCssPageRect)
 {
     NS_ASSERTION(!isNull(), "SetFirstPaintViewport called on null layer client!");
     JNIEnv *env = GetJNIForThread();    // this is called on the compositor thread
     if (!env)
         return;
 
     AutoLocalJNIFrame jniFrame(env, 0);
     return env->CallVoidMethod(wrapped_obj, jSetFirstPaintViewport, (float)aOffset.x, (float)aOffset.y, aZoom,
-                               (float)aPageRect.x, (float)aPageRect.y, (float)aPageRect.XMost(), (float)aPageRect.YMost(),
                                aCssPageRect.x, aCssPageRect.y, aCssPageRect.XMost(), aCssPageRect.YMost());
 }
 
 void
 AndroidGeckoLayerClient::SetPageRect(const CSSRect& aCssPageRect)
 {
     NS_ASSERTION(!isNull(), "SetPageRect called on null layer client!");
     JNIEnv *env = GetJNIForThread();    // this is called on the compositor thread
--- a/widget/android/AndroidJavaWrappers.h
+++ b/widget/android/AndroidJavaWrappers.h
@@ -264,17 +264,17 @@ class AndroidGeckoLayerClient : public W
 public:
     static void InitGeckoLayerClientClass(JNIEnv *jEnv);
 
     void Init(jobject jobj);
 
     AndroidGeckoLayerClient() {}
     AndroidGeckoLayerClient(jobject jobj) { Init(jobj); }
 
-    void SetFirstPaintViewport(const LayerIntPoint& aOffset, float aZoom, const LayerIntRect& aPageRect, const CSSRect& aCssPageRect);
+    void SetFirstPaintViewport(const LayerIntPoint& aOffset, float aZoom, const CSSRect& aCssPageRect);
     void SetPageRect(const CSSRect& aCssPageRect);
     void SyncViewportInfo(const LayerIntRect& aDisplayPort, float aDisplayResolution, bool aLayersUpdated,
                           ScreenPoint& aScrollOffset, float& aScaleX, float& aScaleY,
                           gfx::Margin& aFixedLayerMargins, ScreenPoint& aOffset);
     void SyncFrameMetrics(const gfx::Point& aScrollOffset, float aZoom, const CSSRect& aCssPageRect,
                           bool aLayersUpdated, const CSSRect& aDisplayPort, float aDisplayResolution,
                           bool aIsFirstPaint, gfx::Margin& aFixedLayerMargins, ScreenPoint& aOffset);
     bool ProgressiveUpdateCallback(bool aHasPendingNewThebesContent, const LayerRect& aDisplayPort, float aDisplayResolution, bool aDrawingCritical, gfx::Rect& aViewport, float& aScaleX, float& aScaleY);
--- a/widget/os2/nsWindow.cpp
+++ b/widget/os2/nsWindow.cpp
@@ -41,24 +41,22 @@
 #include "nsIScreenManager.h"
 #include "nsOS2Uni.h"
 #include "nsTHashtable.h"
 #include "nsGkAtoms.h"
 #include "wdgtos2rc.h"
 #include "nsIDOMWheelEvent.h"
 #include "mozilla/Preferences.h"
 #include <os2im.h>
-
+#include <algorithm>    // std::max
 using namespace mozilla;
 using namespace mozilla::widget;
-
 //=============================================================================
 //  Macros
 //=============================================================================
-
 // Drag and Drop
 
 // d&d flags - actions that might cause problems during d&d
 #define ACTION_PAINT    1
 #define ACTION_DRAW     2
 #define ACTION_SCROLL   3
 #define ACTION_SHOW     4
 #define ACTION_PTRPOS   5
@@ -119,27 +117,26 @@ using namespace mozilla::widget;
 
 // extract X & Y from a mouse msg mparam
 #define XFROMMP(m)      (SHORT(LOUSHORT(m)))
 #define YFROMMP(m)      (SHORT(HIUSHORT(m)))
 
 // make these methods seem more appropriate in context
 #define PM2NS_PARENT NS2PM_PARENT
 #define PM2NS NS2PM
-
 // used to identify plugin widgets (copied from nsPluginNativeWindowOS2.cpp)
 #define NS_PLUGIN_WINDOW_PROPERTY_ASSOCIATION \
                         "MozillaPluginWindowPropertyAssociation"
-
 // name of the window class used to clip plugins
 #define kClipWndClass   "nsClipWnd"
+// IME caret not exist
+#define NO_IME_CARET    (static_cast<ULONG>(-1))
 
 //-----------------------------------------------------------------------------
 // Debug
-
 #ifdef DEBUG_FOCUS
   #define DEBUGFOCUS(what) fprintf(stderr, "[%8x]  %8lx  (%02d)  "#what"\n", \
                                    (int)this, mWnd, mWindowIdentifier)
 #else
   #define DEBUGFOCUS(what)
 #endif
 
 //=============================================================================
@@ -2455,60 +2452,45 @@ bool nsWindow::OnQueryConvertPos(MPARAM 
   if (!caret.mSucceeded)
     return false;
 
   pCursorPos->xLeft = caret.mReply.mRect.x;
   pCursorPos->yBottom = caret.mReply.mRect.y;
   pCursorPos->xRight = pCursorPos->xLeft + caret.mReply.mRect.width;
   pCursorPos->yTop = pCursorPos->yBottom + caret.mReply.mRect.height;
   NS2PM(*pCursorPos);
-
   mresult = (MRESULT)QCP_CONVERT;
-
   return true;
 }
 bool nsWindow::ImeResultString(HIMI himi)
 {
-  PCHAR pBuf;
   ULONG ulBufLen;
-
   // Get a buffer size
   ulBufLen = 0;
   if (spfnImGetResultString(himi, IMR_RESULT_RESULTSTRING, NULL, &ulBufLen))
     return false;
-
-  pBuf = new CHAR[ulBufLen];
-  if (!pBuf)
-    return false;
-
-  if (spfnImGetResultString(himi, IMR_RESULT_RESULTSTRING, pBuf,
-                            &ulBufLen)) {
-    delete pBuf;
-
+  nsAutoTArray<CHAR, 64> compositionStringA;
+  compositionStringA.SetCapacity(ulBufLen / sizeof(CHAR));
+
+  if (spfnImGetResultString(himi, IMR_RESULT_RESULTSTRING,
+                            compositionStringA.Elements(), &ulBufLen)) {
     return false;
   }
-
   if (!mIsComposing) {
     mLastDispatchedCompositionString.Truncate();
-
     nsCompositionEvent start(true, NS_COMPOSITION_START, this);
     InitEvent(start);
     DispatchWindowEvent(&start);
-
     mIsComposing = true;
   }
-
   nsAutoChar16Buffer outBuf;
   int32_t outBufLen;
-  MultiByteToWideChar(0, pBuf, ulBufLen, outBuf, outBufLen);
-
-  delete pBuf;
-
+  MultiByteToWideChar(0, compositionStringA.Elements(), ulBufLen,
+                      outBuf, outBufLen);
   nsAutoString compositionString(outBuf.Elements());
-
   if (mLastDispatchedCompositionString != compositionString) {
     nsCompositionEvent update(true, NS_COMPOSITION_UPDATE, this);
     InitEvent(update);
     update.data = compositionString;
     mLastDispatchedCompositionString = compositionString;
     DispatchWindowEvent(&update);
   }
 
@@ -2518,84 +2500,174 @@ bool nsWindow::ImeResultString(HIMI himi
   DispatchWindowEvent(&text);
 
   nsCompositionEvent end(true, NS_COMPOSITION_END, this);
   InitEvent(end);
   end.data = compositionString;
   DispatchWindowEvent(&end);
   mIsComposing = false;
   mLastDispatchedCompositionString.Truncate();
-
   return true;
 }
+static uint32_t
+PlatformToNSAttr(uint8_t aAttr)
+{
+  switch (aAttr)
+  {
+    case CP_ATTR_INPUT_ERROR:
+    case CP_ATTR_INPUT:
+      return NS_TEXTRANGE_RAWINPUT;
+
+    case CP_ATTR_CONVERTED:
+      return NS_TEXTRANGE_CONVERTEDTEXT;
+
+    case CP_ATTR_TARGET_NOTCONVERTED:
+      return NS_TEXTRANGE_SELECTEDRAWTEXT;
+
+    case CP_ATTR_TARGET_CONVERTED:
+      return NS_TEXTRANGE_SELECTEDCONVERTEDTEXT;
+
+    default:
+      MOZ_NOT_REACHED("unknown attribute");
+      return NS_TEXTRANGE_RAWINPUT;
+  }
+}
 
 bool nsWindow::ImeConversionString(HIMI himi)
 {
-  PCHAR pBuf;
   ULONG ulBufLen;
-
   // Get a buffer size
   ulBufLen = 0;
   if (spfnImGetConversionString(himi, IMR_CONV_CONVERSIONSTRING, NULL,
                                 &ulBufLen))
     return false;
-
-  pBuf = new CHAR[ulBufLen];
-  if (!pBuf)
-    return false;
-
-  if (spfnImGetConversionString(himi, IMR_CONV_CONVERSIONSTRING, pBuf,
-                                &ulBufLen)) {
-    delete pBuf;
-
+  nsAutoTArray<CHAR, 64> compositionStringA;
+  compositionStringA.SetCapacity(ulBufLen / sizeof(CHAR));
+
+  if (spfnImGetConversionString(himi, IMR_CONV_CONVERSIONSTRING,
+                                compositionStringA.Elements(), &ulBufLen)) {
     return false;
   }
-
   if (!mIsComposing) {
     mLastDispatchedCompositionString.Truncate();
-
     nsCompositionEvent start(true, NS_COMPOSITION_START, this);
     InitEvent(start);
     DispatchWindowEvent(&start);
-
     mIsComposing = true;
   }
-
   nsAutoChar16Buffer outBuf;
   int32_t outBufLen;
-  MultiByteToWideChar(0, pBuf, ulBufLen, outBuf, outBufLen);
-
-  delete pBuf;
-
+  MultiByteToWideChar(0, compositionStringA.Elements(), ulBufLen,
+                      outBuf, outBufLen);
   nsAutoString compositionString(outBuf.Elements());
-
   // Is a conversion string changed ?
   if (mLastDispatchedCompositionString != compositionString) {
     nsCompositionEvent update(true, NS_COMPOSITION_UPDATE, this);
     InitEvent(update);
     update.data = compositionString;
     mLastDispatchedCompositionString = compositionString;
     DispatchWindowEvent(&update);
   }
-
   nsAutoTArray<nsTextRange, 4> textRanges;
-
   if (!compositionString.IsEmpty()) {
+    bool oneClause = false;
+
+    ulBufLen = 0;
+    if (spfnImGetConversionString(himi, IMR_CONV_CONVERSIONCLAUSE, 0,
+                                  &ulBufLen)) {
+      oneClause = true;  // Assume that there is only one clause
+    }
+
+    ULONG ulClauseCount = std::max(2UL, ulBufLen / sizeof(ULONG));
+    nsAutoTArray<ULONG, 4> clauseOffsets;
+    nsAutoTArray<UCHAR, 4> clauseAttr;
+    ULONG ulCursorPos;
+
+    clauseOffsets.SetCapacity(ulClauseCount);
+    clauseAttr.SetCapacity(ulClauseCount);
+
+    if (spfnImGetConversionString(himi, IMR_CONV_CONVERSIONCLAUSE,
+                                  clauseOffsets.Elements(), &ulBufLen)) {
+      oneClause = true;  // Assume that there is only one clause
+    }
+
+    // Korean IME does not provide clause and cursor infomation
+    // Or if getting a clause inforamtion was failed
+    if (ulBufLen == 0 && !oneClause) {
+      ulCursorPos = compositionString.Length();
+
+      oneClause = true;
+    } else {
+      while (!oneClause) {
+        ulBufLen = 0;
+        if (spfnImGetConversionString(himi, IMR_CONV_CONVERSIONATTR, 0,
+                                      &ulBufLen)) {
+          oneClause = true;
+          break;
+        }
+
+        nsAutoTArray<UCHAR, 64> attr;
+        attr.SetCapacity(ulBufLen / sizeof(UCHAR));
+
+        if (spfnImGetConversionString(himi, IMR_CONV_CONVERSIONATTR,
+                                      attr.Elements(), &ulBufLen)) {
+          oneClause = true;
+          break;
+        }
+
+        // Assume that all the conversion attribute in a clause are same
+        for (ULONG i = 0; i < ulClauseCount - 1; ++i) {
+          clauseAttr[i] = attr[clauseOffsets[i]];
+        }
+
+        // Convert ANSI string offsets to Unicode string offsets
+        clauseOffsets[0] = 0;
+        for (ULONG i = 1; i < ulClauseCount - 1; ++i) {
+          MultiByteToWideChar(0,
+                              compositionStringA.Elements(), clauseOffsets[i],
+                              outBuf, outBufLen);
+          clauseOffsets[i] = outBufLen;
+        }
+        break;
+      }
+
+      ulBufLen = sizeof(ULONG);
+      if (spfnImGetConversionString(himi, IMR_CONV_CURSORPOS, &ulCursorPos,
+                                    &ulBufLen)) {
+        ulCursorPos = NO_IME_CARET;
+      } else {
+        // Convert ANSI string position to Unicode string position
+        MultiByteToWideChar(0, compositionStringA.Elements(), ulCursorPos,
+                            outBuf, outBufLen);
+        ulCursorPos = outBufLen;
+      }
+    }
+
+    if (oneClause) {
+      ulClauseCount = 2;
+      clauseOffsets[0] = 0;
+      clauseOffsets[1] = compositionString.Length();
+      clauseAttr[0] = NS_TEXTRANGE_SELECTEDRAWTEXT;
+    }
+
     nsTextRange newRange;
-    newRange.mStartOffset = 0;
-    newRange.mEndOffset = compositionString.Length();
-    newRange.mRangeType = NS_TEXTRANGE_SELECTEDRAWTEXT;
-    textRanges.AppendElement(newRange);
-
-    newRange.mStartOffset = compositionString.Length();
-    newRange.mEndOffset = newRange.mStartOffset;
-    newRange.mRangeType = NS_TEXTRANGE_CARETPOSITION;
-    textRanges.AppendElement(newRange);
+
+    for (ULONG i = 0; i < ulClauseCount - 1; ++i) {
+      newRange.mStartOffset = clauseOffsets[i];
+      newRange.mEndOffset = clauseOffsets[i + 1];
+      newRange.mRangeType = PlatformToNSAttr(clauseAttr[i]);
+      textRanges.AppendElement(newRange);
+    }
+
+    if (ulCursorPos != NO_IME_CARET) {
+      newRange.mStartOffset = newRange.mEndOffset = ulCursorPos;
+      newRange.mRangeType = NS_TEXTRANGE_CARETPOSITION;
+      textRanges.AppendElement(newRange);
+    }
   }
-
   nsTextEvent text(true, NS_TEXT_TEXT, this);
   InitEvent(text);
   text.theText = compositionString;
   text.rangeArray = textRanges.Elements();
   text.rangeCount = textRanges.Length();
   DispatchWindowEvent(&text);
 
   if (compositionString.IsEmpty()) { // IME conversion was canceled ?