Merge mozilla-central into mozilla-inbound
authorEhsan Akhgari <ehsan@mozilla.com>
Tue, 10 Apr 2012 11:12:26 -0400
changeset 94626 2fd41fea3b27e5ac331b54786b38d30039a03201
parent 94610 3fa30b0edd155100e511fc2bd05dda82fd4666a2 (current diff)
parent 94625 1e947b3674028021e52bc2b4ff0a10c1c09f16a0 (diff)
child 94627 4db1292be760c4ddc632dbf8f5d69d73840b9ce2
child 94629 469e2e5b18e5e0da7446b7823b1fe232fca8672d
push id886
push userlsblakk@mozilla.com
push dateMon, 04 Jun 2012 19:57:52 +0000
treeherdermozilla-beta@bbd8d5efd6d1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone14.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 mozilla-central into mozilla-inbound
--- a/content/base/src/nsRange.cpp
+++ b/content/base/src/nsRange.cpp
@@ -660,17 +660,17 @@ nsRange::ComparePoint(nsIDOMNode* aParen
   if (!nsContentUtils::ContentIsDescendantOf(parent, mRoot)) {
     return NS_ERROR_DOM_WRONG_DOCUMENT_ERR;
   }
   
   if (parent->NodeType() == nsIDOMNode::DOCUMENT_TYPE_NODE) {
     return NS_ERROR_DOM_INVALID_NODE_TYPE_ERR;
   }
 
-  if (aOffset < 0 || aOffset > parent->Length()) {
+  if (aOffset < 0 || PRUint32(aOffset) > parent->Length()) {
     return NS_ERROR_DOM_INDEX_SIZE_ERR;
   }
   
   PRInt32 cmp;
   if ((cmp = nsContentUtils::ComparePoints(parent, aOffset,
                                            mStartParent, mStartOffset)) <= 0) {
     
     *aResult = cmp;
@@ -924,17 +924,17 @@ nsRange::SetStart(nsIDOMNode* aParent, P
 }
 
 /* virtual */ nsresult
 nsRange::SetStart(nsINode* aParent, PRInt32 aOffset)
 {
   nsINode* newRoot = IsValidBoundary(aParent);
   NS_ENSURE_TRUE(newRoot, NS_ERROR_DOM_INVALID_NODE_TYPE_ERR);
 
-  if (aOffset < 0 || aOffset > aParent->Length()) {
+  if (aOffset < 0 || PRUint32(aOffset) > aParent->Length()) {
     return NS_ERROR_DOM_INDEX_SIZE_ERR;
   }
 
   // Collapse if not positioned yet, if positioned in another doc or
   // if the new start is after end.
   if (!mIsPositioned || newRoot != mRoot ||
       nsContentUtils::ComparePoints(aParent, aOffset,
                                     mEndParent, mEndOffset) == 1) {
@@ -988,17 +988,17 @@ nsRange::SetEnd(nsIDOMNode* aParent, PRI
 
 
 /* virtual */ nsresult
 nsRange::SetEnd(nsINode* aParent, PRInt32 aOffset)
 {
   nsINode* newRoot = IsValidBoundary(aParent);
   NS_ENSURE_TRUE(newRoot, NS_ERROR_DOM_INVALID_NODE_TYPE_ERR);
 
-  if (aOffset < 0 || aOffset > aParent->Length()) {
+  if (aOffset < 0 || PRUint32(aOffset) > aParent->Length()) {
     return NS_ERROR_DOM_INDEX_SIZE_ERR;
   }
 
   // Collapse if not positioned yet, if positioned in another doc or
   // if the new end is before start.
   if (!mIsPositioned || newRoot != mRoot ||
       nsContentUtils::ComparePoints(mStartParent, mStartOffset,
                                     aParent, aOffset) == 1) {
--- a/content/html/document/src/nsHTMLDocument.cpp
+++ b/content/html/document/src/nsHTMLDocument.cpp
@@ -555,52 +555,52 @@ nsHTMLDocument::StartDocumentLoad(const 
                                   nsIChannel* aChannel,
                                   nsILoadGroup* aLoadGroup,
                                   nsISupports* aContainer,
                                   nsIStreamListener **aDocListener,
                                   bool aReset,
                                   nsIContentSink* aSink)
 {
   if (!aCommand) {
-    MOZ_NOT_REACHED("Command is mandatory");
+    MOZ_ASSERT(false, "Command is mandatory");
     return NS_ERROR_INVALID_POINTER;
   }
   if (aSink) {
-    MOZ_NOT_REACHED("Got a sink override. Should not happen for HTML doc.");
+    MOZ_ASSERT(false, "Got a sink override. Should not happen for HTML doc.");
     return NS_ERROR_INVALID_ARG;
   }
   if (!mIsRegularHTML) {
-    MOZ_NOT_REACHED("Must not set HTML doc to XHTML mode before load start.");
+    MOZ_ASSERT(false, "Must not set HTML doc to XHTML mode before load start.");
     return NS_ERROR_DOM_INVALID_STATE_ERR;
   }
 
   nsCAutoString contentType;
   aChannel->GetContentType(contentType);
 
   bool view = !strcmp(aCommand, "view") ||
               !strcmp(aCommand, "external-resource");
   bool viewSource = !strcmp(aCommand, "view-source");
   bool asData = !strcmp(aCommand, kLoadAsData);
   if(!(view || viewSource || asData)) {
-    MOZ_NOT_REACHED("Bad parser command");
+    MOZ_ASSERT(false, "Bad parser command");
     return NS_ERROR_INVALID_ARG;
   }
 
   bool html = contentType.EqualsLiteral(TEXT_HTML);
   bool xhtml = !html && contentType.EqualsLiteral(APPLICATION_XHTML_XML);
   bool plainText = !html && !xhtml && (contentType.EqualsLiteral(TEXT_PLAIN) ||
     contentType.EqualsLiteral(TEXT_CSS) ||
     contentType.EqualsLiteral(APPLICATION_JAVASCRIPT) ||
     contentType.EqualsLiteral(APPLICATION_XJAVASCRIPT) ||
     contentType.EqualsLiteral(TEXT_ECMASCRIPT) ||
     contentType.EqualsLiteral(APPLICATION_ECMASCRIPT) ||
     contentType.EqualsLiteral(TEXT_JAVASCRIPT) ||
     contentType.EqualsLiteral(APPLICATION_JSON));
   if (!(html || xhtml || plainText || viewSource)) {
-    MOZ_NOT_REACHED("Channel with bad content type.");
+    MOZ_ASSERT(false, "Channel with bad content type.");
     return NS_ERROR_INVALID_ARG;
   }
 
   bool loadAsHtml5 = true;
 
   if (!viewSource && xhtml) {
       // We're parsing XHTML as XML, remember that.
       mIsRegularHTML = false;
--- a/dom/base/nsScreen.cpp
+++ b/dom/base/nsScreen.cpp
@@ -367,18 +367,25 @@ nsScreen::MozLockOrientation(const nsASt
   }
 
   if (!GetOwner()) {
     *aReturn = false;
     return NS_OK;
   }
 
   if (!IsChromeType(GetOwner()->GetDocShell())) {
+    nsCOMPtr<nsIDOMDocument> doc;
+    GetOwner()->GetDocument(getter_AddRefs(doc));
+    if (!doc) {
+      *aReturn = false;
+      return NS_OK;
+    }
+
     bool fullscreen;
-    GetOwner()->GetFullScreen(&fullscreen);
+    doc->GetMozFullScreen(&fullscreen);
     if (!fullscreen) {
       *aReturn = false;
       return NS_OK;
     }
 
     nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(GetOwner());
     if (!target) {
       *aReturn = false;
--- a/dom/sms/src/ril/SmsDatabaseService.js
+++ b/dom/sms/src/ril/SmsDatabaseService.js
@@ -41,20 +41,16 @@ XPCOMUtils.defineLazyServiceGetter(this,
                                    "nsIIndexedDatabaseManager");
 
 const GLOBAL_SCOPE = this;
 
 /**
  * SmsDatabaseService
  */
 function SmsDatabaseService() {
-  // Prime the directory service's cache to ensure that the ProfD entry exists
-  // by the time IndexedDB queries for it off the main thread. (See bug 743635.)
-  Services.dirsvc.get("ProfD", Ci.nsIFile);
-
   gIDBManager.initWindowless(GLOBAL_SCOPE);
 
   let that = this;
   this.newTxn(READ_ONLY, function(error, txn, store){
     if (error) {
       return;
     }
     // In order to get the highest key value, we open a key cursor in reverse
--- a/gfx/cairo/cairo/src/cairo-compiler-private.h
+++ b/gfx/cairo/cairo/src/cairo-compiler-private.h
@@ -229,16 +229,20 @@ ffs (int x)
 
     if (_BitScanForward(&i, x) != 0)
 	return i + 1;
 
     return 0;
 }
 #endif
 
+#elif defined(__WIN32__) && defined(__GNUC__)
+
+#define ffs(x) __builtin_ffs(x)
+
 #endif
 
 #if defined(_MSC_VER) && defined(_M_IX86)
 /* When compiling with /Gy and /OPT:ICF identical functions will be folded in together.
    The CAIRO_ENSURE_UNIQUE macro ensures that a function is always unique and
    will never be folded into another one. Something like this might eventually
    be needed for GCC but it seems fine for now. */
 #define CAIRO_ENSURE_UNIQUE                       \
new file mode 100644
--- /dev/null
+++ b/gfx/cairo/win32-ffs-gcc.patch
@@ -0,0 +1,25 @@
+diff --git a/gfx/cairo/cairo/src/cairo-compiler-private.h b/gfx/cairo/cairo/src/cairo-compiler-private.h
+index ffac9ce..9a05831 100644
+--- a/gfx/cairo/cairo/src/cairo-compiler-private.h
++++ b/gfx/cairo/cairo/src/cairo-compiler-private.h
+@@ -229,16 +229,20 @@ ffs (int x)
+ 
+     if (_BitScanForward(&i, x) != 0)
+ 	return i + 1;
+ 
+     return 0;
+ }
+ #endif
+ 
++#elif defined(__WIN32__) && defined(__GNUC__)
++
++#define ffs(x) __builtin_ffs(x)
++
+ #endif
+ 
+ #if defined(_MSC_VER) && defined(_M_IX86)
+ /* When compiling with /Gy and /OPT:ICF identical functions will be folded in together.
+    The CAIRO_ENSURE_UNIQUE macro ensures that a function is always unique and
+    will never be folded into another one. Something like this might eventually
+    be needed for GCC but it seems fine for now. */
+ #define CAIRO_ENSURE_UNIQUE                       \
--- a/gfx/thebes/gfxFont.cpp
+++ b/gfx/thebes/gfxFont.cpp
@@ -1495,34 +1495,35 @@ struct GlyphBufferAzure {
 
         gfxContext::AzureState state = aThebesContext->CurrentState();
         if (aDrawMode & gfxFont::GLYPH_FILL) {
             if (state.pattern) {
                 Pattern *pat = state.pattern->GetPattern(aDT, state.patternTransformChanged ? &state.patternTransform : nsnull);
 
                 if (invFontMatrix) {
                     // The brush matrix needs to be multiplied with the inverted matrix
-	                // as well, to move the brush into the space of the glyphs. Before
-	                // the render target transformation
+                    // as well, to move the brush into the space of the glyphs. Before
+                    // the render target transformation
 
                     // This relies on the returned Pattern not to be reused by
                     // others, but regenerated on GetPattern calls. This is true!
-                    Matrix *mat;
+                    Matrix *mat = nsnull;
                     if (pat->GetType() == PATTERN_LINEAR_GRADIENT) {
                         mat = &static_cast<LinearGradientPattern*>(pat)->mMatrix;
                     } else if (pat->GetType() == PATTERN_RADIAL_GRADIENT) {
-                        mat = &static_cast<LinearGradientPattern*>(pat)->mMatrix;
+                        mat = &static_cast<RadialGradientPattern*>(pat)->mMatrix;
                     } else if (pat->GetType() == PATTERN_SURFACE) {
-                        mat = &static_cast<LinearGradientPattern*>(pat)->mMatrix;
+                        mat = &static_cast<SurfacePattern*>(pat)->mMatrix;
                     }
 
-                    *mat = (*mat) * (*invFontMatrix);
+                    if (mat) {
+                        *mat = (*mat) * (*invFontMatrix);
+                    }
                 }
 
-
                 aDT->FillGlyphs(aFont, buf, *pat,
                                 DrawOptions(), aOptions);
             } else if (state.sourceSurface) {
                 aDT->FillGlyphs(aFont, buf, SurfacePattern(state.sourceSurface,
                                                            EXTEND_CLAMP,
                                                            state.surfTransform),
                                 DrawOptions(), aOptions);
             } else {
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -776,18 +776,16 @@ JSRuntime::JSRuntime()
     securityCallbacks(const_cast<JSSecurityCallbacks *>(&NullSecurityCallbacks)),
     destroyPrincipals(NULL),
     structuredCloneCallbacks(NULL),
     telemetryCallback(NULL),
     propertyRemovals(0),
     thousandsSeparator(0),
     decimalSeparator(0),
     numGrouping(0),
-    anynameObject(NULL),
-    functionNamespaceObject(NULL),
     waiveGCQuota(false),
     dtoaState(NULL),
     pendingProxyOperation(NULL),
     trustedPrincipals_(NULL),
     wrapObjectCallback(TransparentObjectWrapper),
     preWrapObjectCallback(NULL),
     preserveWrapperCallback(NULL),
 #ifdef DEBUG
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -562,26 +562,16 @@ struct JSRuntime : js::RuntimeFriendFiel
     int32_t             propertyRemovals;
 
     /* Number localization, used by jsnum.c */
     const char          *thousandsSeparator;
     const char          *decimalSeparator;
     const char          *numGrouping;
 
     /*
-     * Weak references to lazily-created, well-known XML singletons.
-     *
-     * NB: Singleton objects must be carefully disconnected from the rest of
-     * the object graph usually associated with a JSContext's global object,
-     * including the set of standard class objects.  See jsxml.c for details.
-     */
-    JSObject            *anynameObject;
-    JSObject            *functionNamespaceObject;
-
-    /*
      * Flag indicating that we are waiving any soft limits on the GC heap
      * because we want allocations to be infallible (except when we hit OOM).
      */
     bool                waiveGCQuota;
 
     /*
      * The GSN cache is per thread since even multi-cx-per-thread embeddings
      * do not interleave js_GetSrcNote calls.
--- a/layout/base/FrameLayerBuilder.cpp
+++ b/layout/base/FrameLayerBuilder.cpp
@@ -140,16 +140,23 @@ public:
                  ContainerLayer* aContainerLayer,
                  const FrameLayerBuilder::ContainerParameters& aParameters) :
     mBuilder(aBuilder), mManager(aManager),
     mContainerFrame(aContainerFrame), mContainerLayer(aContainerLayer),
     mParameters(aParameters),
     mNextFreeRecycledThebesLayer(0), mNextFreeRecycledColorLayer(0),
     mNextFreeRecycledImageLayer(0), mInvalidateAllThebesContent(false)
   {
+    nsPresContext* presContext = aContainerFrame->PresContext();
+    mAppUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
+    // When AllowResidualTranslation is false, display items will be drawn
+    // scaled with a translation by integer pixels, so we know how the snapping
+    // will work.
+    mSnappingEnabled = aManager->IsSnappingEffectiveTransforms() &&
+      !mParameters.AllowResidualTranslation();
     CollectOldLayers();
   }
 
   void SetInvalidThebesContent(const nsIntRegion& aRegion)
   {
     mInvalidThebesContent = aRegion;
   }
   void SetInvalidateAllThebesContent()
@@ -171,16 +178,40 @@ public:
    * layers as children of the container that aren't in mNewChildLayers.
    * @param aTextContentFlags if any child layer has CONTENT_COMPONENT_ALPHA,
    * set *aTextContentFlags to CONTENT_COMPONENT_ALPHA
    */
   void Finish(PRUint32 *aTextContentFlags);
 
   nsRect GetChildrenBounds() { return mBounds; }
 
+  nscoord GetAppUnitsPerDevPixel() { return mAppUnitsPerDevPixel; }
+
+  nsIntRect ScaleToNearestPixels(const nsRect& aRect)
+  {
+    return aRect.ScaleToNearestPixels(mParameters.mXScale, mParameters.mYScale,
+                                      mAppUnitsPerDevPixel);
+  }
+  nsIntRect ScaleToOutsidePixels(const nsRect& aRect, bool aSnap)
+  {
+    if (aSnap && mSnappingEnabled) {
+      return ScaleToNearestPixels(aRect);
+    }
+    return aRect.ScaleToOutsidePixels(mParameters.mXScale, mParameters.mYScale,
+                                      mAppUnitsPerDevPixel);
+  }
+  nsIntRect ScaleToInsidePixels(const nsRect& aRect, bool aSnap)
+  {
+    if (aSnap && mSnappingEnabled) {
+      return ScaleToNearestPixels(aRect);
+    }
+    return aRect.ScaleToInsidePixels(mParameters.mXScale, mParameters.mYScale,
+                                     mAppUnitsPerDevPixel);
+  }
+
 protected:
   /**
    * We keep a stack of these to represent the ThebesLayers that are
    * currently available to have display items added to.
    * We use a stack here because as much as possible we want to
    * assign display items to existing ThebesLayers, and to the lowest
    * ThebesLayer in z-order. This reduces the number of layers and
    * makes it more likely a display item will be rendered to an opaque
@@ -386,17 +417,19 @@ protected:
   typedef nsAutoTArray<nsRefPtr<Layer>,1> AutoLayersArray;
   AutoLayersArray                  mNewChildLayers;
   nsTArray<nsRefPtr<ThebesLayer> > mRecycledThebesLayers;
   nsTArray<nsRefPtr<ColorLayer> >  mRecycledColorLayers;
   nsTArray<nsRefPtr<ImageLayer> >  mRecycledImageLayers;
   PRUint32                         mNextFreeRecycledThebesLayer;
   PRUint32                         mNextFreeRecycledColorLayer;
   PRUint32                         mNextFreeRecycledImageLayer;
+  nscoord                          mAppUnitsPerDevPixel;
   bool                             mInvalidateAllThebesContent;
+  bool                             mSnappingEnabled;
 };
 
 class ThebesDisplayItemLayerUserData : public LayerUserData
 {
 public:
   ThebesDisplayItemLayerUserData() :
     mForcedBackgroundColor(NS_RGBA(0,0,0,0)),
     mXScale(1.f), mYScale(1.f),
@@ -846,21 +879,17 @@ ContainerState::CreateOrRecycleThebesLay
     if (!layer)
       return nsnull;
     // Mark this layer as being used for Thebes-painting display items
     data = new ThebesDisplayItemLayerUserData();
     layer->SetUserData(&gThebesDisplayItemLayerUserData, data);
   }
   data->mXScale = mParameters.mXScale;
   data->mYScale = mParameters.mYScale;
-  // If we're in a transformed subtree, but no ancestor transform is actively
-  // changing, we'll use the residual translation when drawing into the
-  // ThebesLayer to ensure that snapping exactly matches the ideal transform.
-  layer->SetAllowResidualTranslation(
-      mParameters.mInTransformedSubtree && !mParameters.mInActiveTransformedSubtree);
+  layer->SetAllowResidualTranslation(mParameters.AllowResidualTranslation());
 
   mBuilder->LayerBuilder()->SaveLastPaintOffset(layer);
 
   // Set up transform so that 0,0 in the Thebes layer corresponds to the
   // (pixel-snapped) top-left of the aActiveScrolledRoot.
   nsPoint offset = mBuilder->ToReferenceFrame(aActiveScrolledRoot);
   nscoord appUnitsPerDevPixel = aActiveScrolledRoot->PresContext()->AppUnitsPerDevPixel();
   gfxPoint scaledOffset(
@@ -955,20 +984,18 @@ ContainerState::FindOpaqueBackgroundColo
     intersection.And(candidate->mVisibleRegion, target->mVisibleRegion);
     if (intersection.IsEmpty()) {
       // The layer doesn't intersect our target, ignore it and move on
       continue;
     }
 
     // The candidate intersects our target. If any layer has a solid-color
     // area behind our target, this must be it. Scan its display items.
-    nsPresContext* presContext = mContainerFrame->PresContext();
-    nscoord appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
     nsRect rect =
-      target->mVisibleRegion.GetBounds().ToAppUnits(appUnitsPerDevPixel);
+      target->mVisibleRegion.GetBounds().ToAppUnits(mAppUnitsPerDevPixel);
     rect.ScaleInverseRoundOut(mParameters.mXScale, mParameters.mYScale);
     return mBuilder->LayerBuilder()->
       FindOpaqueColorCovering(mBuilder, candidate->mLayer, rect);
   }
   return NS_RGBA(0,0,0,0);
 }
 
 already_AddRefed<ImageContainer>
@@ -1004,20 +1031,17 @@ ContainerState::PopThebesLayerData()
         // The layer's current transform is applied first, then the result is scaled.
         gfx3DMatrix transform = imageLayer->GetTransform()*
           gfx3DMatrix::ScalingMatrix(mParameters.mXScale, mParameters.mYScale, 1.0f);
         imageLayer->SetTransform(transform);
       }
       NS_ASSERTION(data->mImageClip.mRoundedClipRects.IsEmpty(),
                    "How did we get rounded clip rects here?");
       if (data->mImageClip.mHaveClipRect) {
-        nsPresContext* presContext = mContainerFrame->PresContext();
-        nscoord appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
-        nsIntRect clip = data->mImageClip.mClipRect.ScaleToNearestPixels(
-            mParameters.mXScale, mParameters.mYScale, appUnitsPerDevPixel);
+        nsIntRect clip = ScaleToNearestPixels(data->mImageClip.mClipRect);
         imageLayer->IntersectClipRect(clip);
       }
       layer = imageLayer;
     } else {
       nsRefPtr<ColorLayer> colorLayer = CreateOrRecycleColorLayer();
       colorLayer->SetIsFixedPosition(data->mLayer->GetIsFixedPosition());
       colorLayer->SetColor(data->mSolidColor);
 
@@ -1173,20 +1197,27 @@ ContainerState::ThebesLayerData::Accumul
   } else {
     mImage = nsnull;
   }
 
   // Some display items have to exist (so they can set forceTransparentSurface
   // below) but don't draw anything. They'll return true for isUniform but
   // a color with opacity 0.
   if (!isUniform || NS_GET_A(uniformColor) > 0) {
-    if (isUniform &&
-        aItem->GetBounds(aState->mBuilder).ScaleToInsidePixels(
-            aState->mParameters.mXScale, aState->mParameters.mYScale,
-            AppUnitsPerDevPixel(aItem)).Contains(aVisibleRect)) {
+    // Make sure that the visible area is covered by uniform pixels. In
+    // particular this excludes cases where the edges of the item are not
+    // pixel-aligned (thus the item will not be truly uniform).
+    if (isUniform) {
+      bool snap;
+      nsRect bounds = aItem->GetBounds(aState->mBuilder, &snap);
+      if (!aState->ScaleToInsidePixels(bounds, snap).Contains(aVisibleRect)) {
+        isUniform = false;
+      }
+    }
+    if (isUniform) {
       if (mVisibleRegion.IsEmpty()) {
         // This color is all we have
         mSolidColor = uniformColor;
         mIsSolidColorInVisibleRegion = true;
       } else if (mIsSolidColorInVisibleRegion &&
                  mVisibleRegion.IsEqual(nsIntRegion(aVisibleRect))) {
         // we can just blend the colors together
         mSolidColor = NS_ComposeColors(mSolidColor, uniformColor);
@@ -1198,30 +1229,30 @@ ContainerState::ThebesLayerData::Accumul
     }
 
     mVisibleRegion.Or(mVisibleRegion, aVisibleRect);
     mVisibleRegion.SimplifyOutward(4);
     mDrawRegion.Or(mDrawRegion, aDrawRect);
     mDrawRegion.SimplifyOutward(4);
   }
   
-  bool forceTransparentSurface = false;
-  nsRegion opaque = aItem->GetOpaqueRegion(aState->mBuilder, &forceTransparentSurface);
+  bool forceTransparentSurface;
+  bool snap;
+  nsRegion opaque = aItem->GetOpaqueRegion(aState->mBuilder, &snap,
+                                           &forceTransparentSurface);
   if (!opaque.IsEmpty()) {
     nsRegionRectIterator iter(opaque);
-    nscoord appUnitsPerDevPixel = AppUnitsPerDevPixel(aItem);
     for (const nsRect* r = iter.Next(); r; r = iter.Next()) {
       // We don't use SimplifyInward here since it's not defined exactly
       // what it will discard. For our purposes the most important case
       // is a large opaque background at the bottom of z-order (e.g.,
       // a canvas background), so we need to make sure that the first rect
       // we see doesn't get discarded.
-      nsIntRect rect = aClip.ApproximateIntersect(*r).ScaleToInsidePixels(
-          aState->mParameters.mXScale, aState->mParameters.mYScale,
-          appUnitsPerDevPixel);
+      nsIntRect rect =
+        aState->ScaleToInsidePixels(aClip.ApproximateIntersect(*r), snap);
       nsIntRegion tmp;
       tmp.Or(mOpaqueRegion, rect);
        // Opaque display items in chrome documents whose window is partially
        // transparent are always added to the opaque region. This helps ensure
        // that we get as much subpixel-AA as possible in the chrome.
        if (tmp.GetNumRects() <= 4 ||
            (WindowHasTransparency(aState->mBuilder) &&
             aItem->GetUnderlyingFrame()->PresContext()->IsChrome())) {
@@ -1232,21 +1263,20 @@ ContainerState::ThebesLayerData::Accumul
   if (aState->mParameters.mDisableSubpixelAntialiasingInDescendants) {
     // Disable component alpha. This is cheaper than calling GetComponentAlphaBounds since for
     // most items this is a single virtual call that does nothing.
     // Note that the transform (if any) on the ThebesLayer is always an integer translation so
     // we don't have to factor that in here.
     aItem->DisableComponentAlpha();
   } else {
     nsRect componentAlpha = aItem->GetComponentAlphaBounds(aState->mBuilder);
-    componentAlpha.IntersectRect(componentAlpha, aItem->GetVisibleRect());
     if (!componentAlpha.IsEmpty()) {
-      nscoord appUnitsPerDevPixel = AppUnitsPerDevPixel(aItem);
-      if (!mOpaqueRegion.Contains(componentAlpha.ScaleToOutsidePixels(
-          aState->mParameters.mXScale, aState->mParameters.mYScale, appUnitsPerDevPixel))) {
+      nsIntRect componentAlphaRect =
+        aState->ScaleToOutsidePixels(componentAlpha, false).Intersect(aVisibleRect);
+      if (!mOpaqueRegion.Contains(componentAlphaRect)) {
         if (SuppressComponentAlpha(aState->mBuilder, aItem, componentAlpha)) {
           aItem->DisableComponentAlpha();
         } else {
           mNeedComponentAlpha = true;
         }
       }
     }
   }
@@ -1393,41 +1423,39 @@ PaintInactiveLayer(nsDisplayListBuilder*
  * We set the visible rect for all layers, although the actual setting
  * of visible rects for some ThebesLayers is deferred until the calling
  * of ContainerState::Finish.
  */
 void
 ContainerState::ProcessDisplayItems(const nsDisplayList& aList,
                                     FrameLayerBuilder::Clip& aClip)
 {
-  PRInt32 appUnitsPerDevPixel =
-    mContainerFrame->PresContext()->AppUnitsPerDevPixel();
-
   for (nsDisplayItem* item = aList.GetBottom(); item; item = item->GetAbove()) {
     nsDisplayItem::Type type = item->GetType();
     if (type == nsDisplayItem::TYPE_CLIP ||
         type == nsDisplayItem::TYPE_CLIP_ROUNDED_RECT) {
       FrameLayerBuilder::Clip childClip(aClip, item);
       ProcessDisplayItems(*item->GetList(), childClip);
       continue;
     }
 
-    NS_ASSERTION(appUnitsPerDevPixel == AppUnitsPerDevPixel(item),
+    NS_ASSERTION(mAppUnitsPerDevPixel == AppUnitsPerDevPixel(item),
       "items in a container layer should all have the same app units per dev pixel");
 
     nsIntRect itemVisibleRect =
-      item->GetVisibleRect().ScaleToOutsidePixels(
-          mParameters.mXScale, mParameters.mYScale, appUnitsPerDevPixel);
-    nsRect itemContent = item->GetBounds(mBuilder);
+      ScaleToOutsidePixels(item->GetVisibleRect(), false);
+    bool snap;
+    nsRect itemContent = item->GetBounds(mBuilder, &snap);
     if (aClip.mHaveClipRect) {
       itemContent.IntersectRect(aClip.mClipRect, itemContent);
     }
     mBounds.UnionRect(mBounds, itemContent);
-    nsIntRect itemDrawRect = itemContent.ScaleToOutsidePixels(
-        mParameters.mXScale, mParameters.mYScale, appUnitsPerDevPixel);
+    nsIntRect itemDrawRect = ScaleToOutsidePixels(itemContent, snap);
+    itemVisibleRect.IntersectRect(itemVisibleRect, itemDrawRect);
+
     LayerState layerState = item->GetLayerState(mBuilder, mManager);
 
     nsIFrame* activeScrolledRoot =
       nsLayoutUtils::GetActiveScrolledRootFor(item, mBuilder);
 
     // Assign the item to a layer
     if (layerState == LAYER_ACTIVE_FORCE ||
         layerState == LAYER_ACTIVE_EMPTY ||
@@ -1476,18 +1504,17 @@ ContainerState::ProcessDisplayItems(cons
       NS_ASSERTION(!ownLayer->HasUserData(&gLayerManagerUserData),
                    "We shouldn't have a FrameLayerBuilder-managed layer here!");
       NS_ASSERTION(aClip.mHaveClipRect ||
                      aClip.mRoundedClipRects.IsEmpty(),
                    "If we have rounded rects, we must have a clip rect");
       // It has its own layer. Update that layer's clip and visible rects.
       if (aClip.mHaveClipRect) {
         ownLayer->IntersectClipRect(
-            aClip.NonRoundedIntersection().ScaleToNearestPixels(
-                mParameters.mXScale, mParameters.mYScale, appUnitsPerDevPixel));
+          ScaleToNearestPixels(aClip.NonRoundedIntersection()));
       }
       ThebesLayerData* data = GetTopThebesLayerData();
       if (data) {
         data->mVisibleAboveRegion.Or(data->mVisibleAboveRegion, itemVisibleRect);
         data->mVisibleAboveRegion.SimplifyOutward(4);
         // Add the entire bounds rect to the mDrawAboveRegion.
         // The visible region may be excluding opaque content above the
         // item, and we need to ensure that that content is not placed
@@ -1537,44 +1564,41 @@ ContainerState::InvalidateForLayerChange
     return;
   }
   if (aNewLayer != oldLayer) {
     // The item has changed layers.
     // Invalidate the bounds in the old layer and new layer.
     // The bounds might have changed, but we assume that any difference
     // in the bounds will have been invalidated for all Thebes layers
     // in the container via regular frame invalidation.
-    nsRect bounds = aItem->GetBounds(mBuilder);
-    PRInt32 appUnitsPerDevPixel = AppUnitsPerDevPixel(aItem);
+    bool snap;
+    nsRect bounds = aItem->GetBounds(mBuilder, &snap);
 
     ThebesLayer* t = oldLayer->AsThebesLayer();
     if (t) {
       ThebesDisplayItemLayerUserData* data =
           static_cast<ThebesDisplayItemLayerUserData*>(t->GetUserData(&gThebesDisplayItemLayerUserData));
       // Note that whenever the layer's scale changes, we invalidate the whole thing,
       // so it doesn't matter whether we are using the old scale at last paint
       // or a new scale here
       InvalidatePostTransformRegion(t,
-          bounds.ScaleToOutsidePixels(data->mXScale, data->mYScale, appUnitsPerDevPixel),
+          bounds.ScaleToOutsidePixels(data->mXScale, data->mYScale, mAppUnitsPerDevPixel),
           mBuilder->LayerBuilder()->GetLastPaintOffset(t));
     }
     if (aNewLayer) {
       ThebesLayer* newLayer = aNewLayer->AsThebesLayer();
       if (newLayer) {
         ThebesDisplayItemLayerUserData* data =
             static_cast<ThebesDisplayItemLayerUserData*>(newLayer->GetUserData(&gThebesDisplayItemLayerUserData));
         InvalidatePostTransformRegion(newLayer,
-            bounds.ScaleToOutsidePixels(data->mXScale, data->mYScale, appUnitsPerDevPixel),
+            bounds.ScaleToOutsidePixels(data->mXScale, data->mYScale, mAppUnitsPerDevPixel),
             GetTranslationForThebesLayer(newLayer));
       }
     }
 
-    NS_ASSERTION(appUnitsPerDevPixel ==
-                   mContainerFrame->PresContext()->AppUnitsPerDevPixel(),
-                 "app units per dev pixel should be constant in a container");
     mContainerFrame->InvalidateWithFlags(
         bounds - mBuilder->ToReferenceFrame(mContainerFrame),
         nsIFrame::INVALIDATE_NO_THEBES_LAYERS |
         nsIFrame::INVALIDATE_EXCLUDE_CURRENT_PAINT);
   }
 }
 
 bool
@@ -1855,17 +1879,16 @@ FrameLayerBuilder::BuildContainerLayerFo
     return containerLayer.forget();
   }
 
   ContainerParameters scaleParameters =
     ChooseScaleAndSetTransform(this, aContainerFrame, aTransform, aParameters,
                                containerLayer);
   ContainerState state(aBuilder, aManager, aContainerFrame, containerLayer,
                        scaleParameters);
-  nscoord appUnitsPerDevPixel = aContainerFrame->PresContext()->AppUnitsPerDevPixel();
 
   if (aManager == mRetainingManager) {
     DisplayItemDataEntry* entry = mNewDisplayItemData.PutEntry(aContainerFrame);
     if (entry) {
       entry->mData.AppendElement(
           DisplayItemData(containerLayer, containerDisplayItemKey, LAYER_ACTIVE));
     }
 
@@ -1875,17 +1898,17 @@ FrameLayerBuilder::BuildContainerLayerFo
 
     nsRegion* invalidThebesContent(static_cast<nsRegion*>
       (props.Get(ThebesLayerInvalidRegionProperty())));
     if (invalidThebesContent) {
       nsPoint offset = offsetAtLastPaint ? *offsetAtLastPaint : currentOffset;
       invalidThebesContent->MoveBy(offset);
       state.SetInvalidThebesContent(invalidThebesContent->
         ScaleToOutsidePixels(scaleParameters.mXScale, scaleParameters.mYScale,
-                             appUnitsPerDevPixel));
+                             state.GetAppUnitsPerDevPixel()));
       // We have to preserve the current contents of invalidThebesContent
       // because there might be multiple container layers for the same
       // frame and we need to invalidate the ThebesLayer children of all
       // of them.
       invalidThebesContent->MoveBy(-offset);
     } else {
       // The region was deleted to indicate that everything should be
       // invalidated.
@@ -1900,25 +1923,23 @@ FrameLayerBuilder::BuildContainerLayerFo
   // Set CONTENT_COMPONENT_ALPHA if any of our children have it.
   // This is suboptimal ... a child could have text that's over transparent
   // pixels in its own layer, but over opaque parts of previous siblings.
   PRUint32 flags;
   state.Finish(&flags);
 
   nsRect bounds = state.GetChildrenBounds();
   NS_ASSERTION(bounds.IsEqualInterior(aChildren.GetBounds(aBuilder)), "Wrong bounds");
-  nsIntRect pixBounds =
-    bounds.ScaleToOutsidePixels(scaleParameters.mXScale, scaleParameters.mYScale,
-                                appUnitsPerDevPixel);
+  nsIntRect pixBounds = state.ScaleToOutsidePixels(bounds, false);
   containerLayer->SetVisibleRegion(pixBounds);
   // Make sure that rounding the visible region out didn't add any area
   // we won't paint
   if (aChildren.IsOpaque() && !aChildren.NeedsTransparentSurface()) {
     bounds.ScaleRoundIn(scaleParameters.mXScale, scaleParameters.mYScale);
-    if (bounds.Contains(pixBounds.ToAppUnits(appUnitsPerDevPixel))) {
+    if (bounds.Contains(pixBounds.ToAppUnits(state.GetAppUnitsPerDevPixel()))) {
       // Clear CONTENT_COMPONENT_ALPHA
       flags = Layer::CONTENT_OPAQUE;
     }
   }
   containerLayer->SetContentFlags(flags);
 
   return containerLayer.forget();
 }
@@ -2041,17 +2062,18 @@ FrameLayerBuilder::GetDedicatedLayer(nsI
     }
   }
   return nsnull;
 }
 
 #ifdef MOZ_DUMP_PAINTING
 static void DebugPaintItem(nsRenderingContext* aDest, nsDisplayItem *aItem, nsDisplayListBuilder* aBuilder)
 {
-  nsRect appUnitBounds = aItem->GetBounds(aBuilder);
+  bool snap;
+  nsRect appUnitBounds = aItem->GetBounds(aBuilder, &snap);
   gfxRect bounds(appUnitBounds.x, appUnitBounds.y, appUnitBounds.width, appUnitBounds.height);
   bounds.ScaleInverse(aDest->AppUnitsPerDevPixel());
 
   nsRefPtr<gfxASurface> surf = 
     gfxPlatform::GetPlatform()->CreateOffscreenSurface(gfxIntSize(bounds.width, bounds.height), 
                                                        gfxASurface::CONTENT_COLOR_ALPHA);
   surf->SetDeviceOffset(-bounds.TopLeft());
   nsRefPtr<gfxContext> context = new gfxContext(surf);
--- a/layout/base/FrameLayerBuilder.h
+++ b/layout/base/FrameLayerBuilder.h
@@ -158,16 +158,27 @@ public:
       mInTransformedSubtree(aParent.mInTransformedSubtree),
       mInActiveTransformedSubtree(aParent.mInActiveTransformedSubtree),
       mDisableSubpixelAntialiasingInDescendants(aParent.mDisableSubpixelAntialiasingInDescendants)
     {}
     float mXScale, mYScale;
     bool mInTransformedSubtree;
     bool mInActiveTransformedSubtree;
     bool mDisableSubpixelAntialiasingInDescendants;
+    /**
+     * When this is false, ThebesLayer coordinates are drawn to with an integer
+     * translation and the scale in mXScale/mYScale.
+     */
+    bool AllowResidualTranslation()
+    {
+      // If we're in a transformed subtree, but no ancestor transform is actively
+      // changing, we'll use the residual translation when drawing into the
+      // ThebesLayer to ensure that snapping exactly matches the ideal transform.
+      return mInTransformedSubtree && !mInActiveTransformedSubtree;
+    }
   };
   /**
    * Build a container layer for a display item that contains a child
    * list, either reusing an existing one or creating a new one. It
    * sets the container layer children to layers which together render
    * the contents of the display list. It reuses existing layers from
    * the retained layer manager if possible.
    * aContainer may be null, in which case we construct a root layer.
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -83,17 +83,16 @@ nsDisplayListBuilder::nsDisplayListBuild
       mHadToIgnoreSuppression(false),
       mIsAtRootOfPseudoStackingContext(false),
       mIncludeAllOutOfFlows(false),
       mSelectedFramesOnly(false),
       mAccurateVisibleRegions(false),
       mInTransform(false),
       mSyncDecodeImages(false),
       mIsPaintingToWindow(false),
-      mSnappingEnabled(mMode != EVENT_DELIVERY),
       mHasDisplayPort(false),
       mHasFixedItems(false)
 {
   MOZ_COUNT_CTOR(nsDisplayListBuilder);
   PL_InitArenaPool(&mPool, "displayListArena", 1024,
                    NS_MAX(NS_ALIGNMENT_OF(void*),NS_ALIGNMENT_OF(double))-1);
 
   nsPresContext* pc = aReferenceFrame->PresContext();
@@ -410,42 +409,44 @@ nsDisplayList::FlattenTo(nsTArray<nsDisp
     }
   }
 }
 
 nsRect
 nsDisplayList::GetBounds(nsDisplayListBuilder* aBuilder) const {
   nsRect bounds;
   for (nsDisplayItem* i = GetBottom(); i != nsnull; i = i->GetAbove()) {
-    bounds.UnionRect(bounds, i->GetBounds(aBuilder));
+    bool snap;
+    bounds.UnionRect(bounds, i->GetBounds(aBuilder, &snap));
   }
   return bounds;
 }
 
 bool
 nsDisplayList::ComputeVisibilityForRoot(nsDisplayListBuilder* aBuilder,
                                         nsRegion* aVisibleRegion) {
   nsRegion r;
   r.And(*aVisibleRegion, GetBounds(aBuilder));
   return ComputeVisibilityForSublist(aBuilder, aVisibleRegion, r.GetBounds(), r.GetBounds());
 }
 
 static nsRegion
 TreatAsOpaque(nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder,
               bool* aTransparentBackground)
 {
-  nsRegion opaque = aItem->GetOpaqueRegion(aBuilder, aTransparentBackground);
+  bool snap;
+  nsRegion opaque = aItem->GetOpaqueRegion(aBuilder, &snap, aTransparentBackground);
   if (aBuilder->IsForPluginGeometry()) {
     // Treat all chrome items as opaque, unless their frames are opacity:0.
     // Since opacity:0 frames generate an nsDisplayOpacity, that item will
     // not be treated as opaque here, so opacity:0 chrome content will be
     // effectively ignored, as it should be.
     nsIFrame* f = aItem->GetUnderlyingFrame();
     if (f && f->PresContext()->IsChrome() && f->GetStyleDisplay()->mOpacity != 0.0) {
-      opaque = aItem->GetBounds(aBuilder);
+      opaque = aItem->GetBounds(aBuilder, &snap);
     }
   }
   return opaque;
 }
 
 static nsRect
 GetDisplayPortBounds(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem)
 {
@@ -468,16 +469,17 @@ GetDisplayPortBounds(nsDisplayListBuilde
   return result;
 }
 
 bool
 nsDisplayList::ComputeVisibilityForSublist(nsDisplayListBuilder* aBuilder,
                                            nsRegion* aVisibleRegion,
                                            const nsRect& aListVisibleBounds,
                                            const nsRect& aAllowVisibleRegionExpansion) {
+  bool snap;
 #ifdef DEBUG
   nsRegion r;
   r.And(*aVisibleRegion, GetBounds(aBuilder));
   NS_ASSERTION(r.GetBounds().IsEqualInterior(aListVisibleBounds),
                "bad aListVisibleBounds");
 #endif
   mVisibleRect = aListVisibleBounds;
   bool anyVisible = false;
@@ -502,17 +504,17 @@ nsDisplayList::ComputeVisibilityForSubli
       // The elements on the list >= i no longer serve any use.
       elements.SetLength(i);
       list->FlattenTo(&elements);
       i = elements.Length();
       item->~nsDisplayItem();
       continue;
     }
 
-    nsRect bounds = item->GetBounds(aBuilder);
+    nsRect bounds = item->GetBounds(aBuilder, &snap);
 
     nsRegion itemVisible;
     if (ForceVisiblityForFixedItem(aBuilder, item)) {
       itemVisible.And(GetDisplayPortBounds(aBuilder, item), bounds);
     } else {
       itemVisible.And(*aVisibleRegion, bounds);
     }
     item->mVisibleRect = itemVisible.GetBounds();
@@ -737,17 +739,18 @@ void nsDisplayList::HitTest(nsDisplayLis
   }
   nsAutoTArray<FramesWithDepth, 16> temp;
   for (PRInt32 i = aState->mItemBuffer.Length() - 1; i >= itemBufferStart; --i) {
     // Pop element off the end of the buffer. We want to shorten the buffer
     // so that recursive calls to HitTest have more buffer space.
     item = aState->mItemBuffer[i];
     aState->mItemBuffer.SetLength(i);
 
-    if (aRect.Intersects(item->GetBounds(aBuilder))) {
+    bool snap;
+    if (aRect.Intersects(item->GetBounds(aBuilder, &snap))) {
       nsAutoTArray<nsIFrame*, 16> outFrames;
       item->HitTest(aBuilder, aRect, aState, &outFrames);
       
       // For 3d transforms with preserve-3d we add hit frames into the temp list 
       // so we can sort them later, otherwise we add them directly to the output list.
       nsTArray<nsIFrame*> *writeFrames = aOutFrames;
       if (item->GetType() == nsDisplayItem::TYPE_TRANSFORM &&
           item->GetUnderlyingFrame()->Preserves3D()) {
@@ -890,17 +893,18 @@ void nsDisplayList::SortByContentOrder(n
 void nsDisplayList::Sort(nsDisplayListBuilder* aBuilder,
                          SortLEQ aCmp, void* aClosure) {
   ExplodeAnonymousChildLists(aBuilder);
   ::Sort(this, Count(), aCmp, aClosure);
 }
 
 bool nsDisplayItem::RecomputeVisibility(nsDisplayListBuilder* aBuilder,
                                           nsRegion* aVisibleRegion) {
-  nsRect bounds = GetBounds(aBuilder);
+  bool snap;
+  nsRect bounds = GetBounds(aBuilder, &snap);
 
   nsRegion itemVisible;
   if (ForceVisiblityForFixedItem(aBuilder, this)) {
     itemVisible.And(GetDisplayPortBounds(aBuilder, this), bounds);
   } else {
     itemVisible.And(*aVisibleRegion, bounds);
   }
   mVisibleRect = itemVisible.GetBounds();
@@ -912,36 +916,21 @@ bool nsDisplayItem::RecomputeVisibility(
     return false;
 
   bool forceTransparentBackground;
   nsRegion opaque = TreatAsOpaque(this, aBuilder, &forceTransparentBackground);
   aBuilder->SubtractFromVisibleRegion(aVisibleRegion, opaque);
   return true;
 }
 
-// Note that even if the rectangle we draw and snap is smaller than aRect,
-// it's OK to call this to get a bounding rect for what we'll draw, because
-// snapping a rectangle which is contained in R always gives you a
-// rectangle which is contained in the snapped R.
-static nsRect
-SnapBounds(bool aSnappingEnabled, nsPresContext* aPresContext,
-           const nsRect& aRect) {
-  nsRect r = aRect;
-  if (aSnappingEnabled) {
-    nscoord appUnitsPerDevPixel = aPresContext->AppUnitsPerDevPixel();
-    r = r.ToNearestPixels(appUnitsPerDevPixel).ToAppUnits(appUnitsPerDevPixel);
-  }
-  return r;
-}
-
 nsRect
-nsDisplaySolidColor::GetBounds(nsDisplayListBuilder* aBuilder)
+nsDisplaySolidColor::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap)
 {
-  nsPresContext* presContext = mFrame->PresContext();
-  return SnapBounds(mSnappingEnabled, presContext, mBounds);
+  *aSnap = true;
+  return mBounds;
 }
 
 void
 nsDisplaySolidColor::Paint(nsDisplayListBuilder* aBuilder,
                            nsRenderingContext* aCtx)
 {
   aCtx->SetColor(mColor);
   aCtx->FillRect(mVisibleRect);
@@ -963,18 +952,17 @@ RegisterThemeGeometry(nsDisplayListBuild
 
   nsRect borderBox(aFrame->GetOffsetTo(displayRoot), aFrame->GetSize());
   aBuilder->RegisterThemeGeometry(aFrame->GetStyleDisplay()->mAppearance,
       borderBox.ToNearestPixels(aFrame->PresContext()->AppUnitsPerDevPixel()));
 }
 
 nsDisplayBackground::nsDisplayBackground(nsDisplayListBuilder* aBuilder,
                                          nsIFrame* aFrame)
-  : nsDisplayItem(aBuilder, aFrame),
-    mSnappingEnabled(aBuilder->IsSnappingEnabled() && !aBuilder->IsInTransform())
+  : nsDisplayItem(aBuilder, aFrame)
 {
   MOZ_COUNT_CTOR(nsDisplayBackground);
   const nsStyleDisplay* disp = mFrame->GetStyleDisplay();
   mIsThemed = mFrame->IsThemed(disp, &mThemeTransparency);
 
   if (mIsThemed) {
     // Perform necessary RegisterThemeGeometry
     if (disp->mAppearance == NS_THEME_MOZ_MAC_UNIFIED_TOOLBAR ||
@@ -1121,17 +1109,18 @@ nsDisplayBackground::ComputeVisibility(n
   // anything.
   nsStyleContext* bgSC;
   return mIsThemed ||
     nsCSSRendering::FindBackground(mFrame->PresContext(), mFrame, &bgSC);
 }
 
 nsRegion
 nsDisplayBackground::GetInsideClipRegion(nsPresContext* aPresContext,
-                                         PRUint8 aClip, const nsRect& aRect)
+                                         PRUint8 aClip, const nsRect& aRect,
+                                         bool* aSnap)
 {
   nsRegion result;
   if (aRect.IsEmpty())
     return result;
 
   nscoord radii[8];
   nsRect clipRect;
   bool haveRadii;
@@ -1148,75 +1137,75 @@ nsDisplayBackground::GetInsideClipRegion
     haveRadii = mFrame->GetContentBoxBorderRadii(radii);
     clipRect = mFrame->GetContentRect() - mFrame->GetPosition() + ToReferenceFrame();
     break;
   default:
     NS_NOTREACHED("Unknown clip type");
     return result;
   }
 
-  nsRect inputRect = SnapBounds(mSnappingEnabled, aPresContext, aRect);
-  clipRect = SnapBounds(mSnappingEnabled, aPresContext, clipRect);
-
   if (haveRadii) {
-    result = nsLayoutUtils::RoundedRectIntersectRect(clipRect, radii, inputRect);
+    *aSnap = false;
+    result = nsLayoutUtils::RoundedRectIntersectRect(clipRect, radii, aRect);
   } else {
     nsRect r;
-    r.IntersectRect(clipRect, inputRect);
+    r.IntersectRect(clipRect, aRect);
     result = r;
   }
   return result;
 }
 
 nsRegion
 nsDisplayBackground::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
+                                     bool* aSnap,
                                      bool* aForceTransparentSurface) {
   nsRegion result;
-  if (aForceTransparentSurface) {
-    *aForceTransparentSurface = false;
-  }
+  *aSnap = false;
+  *aForceTransparentSurface = false;
   // theme background overrides any other background
   if (mIsThemed) {
     if (aForceTransparentSurface) {
       const nsStyleDisplay* disp = mFrame->GetStyleDisplay();
       *aForceTransparentSurface = disp->mAppearance == NS_THEME_WIN_BORDERLESS_GLASS ||
                                   disp->mAppearance == NS_THEME_WIN_GLASS;
     }
     if (mThemeTransparency == nsITheme::eOpaque) {
-      result = GetBounds(aBuilder);
+      result = GetBounds(aBuilder, aSnap);
     }
     return result;
   }
 
   nsStyleContext* bgSC;
   nsPresContext* presContext = mFrame->PresContext();
   if (!nsCSSRendering::FindBackground(mFrame->PresContext(), mFrame, &bgSC))
     return result;
   const nsStyleBackground* bg = bgSC->GetStyleBackground();
   const nsStyleBackground::Layer& bottomLayer = bg->BottomLayer();
 
+  *aSnap = true;
+
   nsRect borderBox = nsRect(ToReferenceFrame(), mFrame->GetSize());
   if (NS_GET_A(bg->mBackgroundColor) == 255 &&
       !nsCSSRendering::IsCanvasFrame(mFrame)) {
-    result = GetInsideClipRegion(presContext, bottomLayer.mClip, borderBox);
+    result = GetInsideClipRegion(presContext, bottomLayer.mClip, borderBox, aSnap);
   }
 
   // For policies other than EACH_BOX, don't try to optimize here, since
   // this could easily lead to O(N^2) behavior inside InlineBackgroundData,
   // which expects frames to be sent to it in content order, not reverse
   // content order which we'll produce here.
   // Of course, if there's only one frame in the flow, it doesn't matter.
   if (bg->mBackgroundInlinePolicy == NS_STYLE_BG_INLINE_POLICY_EACH_BOX ||
       (!mFrame->GetPrevContinuation() && !mFrame->GetNextContinuation())) {
     NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT(i, bg) {
       const nsStyleBackground::Layer& layer = bg->mLayers[i];
       if (layer.mImage.IsOpaque()) {
         nsRect r = nsCSSRendering::GetBackgroundLayerRect(presContext, mFrame,
             borderBox, *bg, layer);
-        result.Or(result, GetInsideClipRegion(presContext, layer.mClip, r));
+        result.Or(result, GetInsideClipRegion(presContext, layer.mClip, r, aSnap));
       }
     }
   }
 
   return result;
 }
 
 bool
@@ -1305,17 +1294,18 @@ nsDisplayBackground::ShouldFixToViewport
     }
     if (layer.mClip != NS_STYLE_BG_CLIP_BORDER)
       return false;
   }
 
   if (nsLayoutUtils::HasNonZeroCorner(mFrame->GetStyleBorder()->mBorderRadius))
     return false;
 
-  nsRect bounds = GetBounds(aBuilder);
+  bool snap;
+  nsRect bounds = GetBounds(aBuilder, &snap);
   nsIFrame* rootScrollFrame = presContext->PresShell()->GetRootScrollFrame();
   if (!rootScrollFrame)
     return false;
   nsIScrollableFrame* scrollable = do_QueryFrame(rootScrollFrame);
   nsRect scrollport = scrollable->GetScrollPortRect() +
     aBuilder->ToReferenceFrame(rootScrollFrame);
   return bounds.Contains(scrollport);
 }
@@ -1332,31 +1322,33 @@ nsDisplayBackground::Paint(nsDisplayList
   }
   nsCSSRendering::PaintBackground(mFrame->PresContext(), *aCtx, mFrame,
                                   mVisibleRect,
                                   nsRect(offset, mFrame->GetSize()),
                                   flags);
 }
 
 nsRect
-nsDisplayBackground::GetBounds(nsDisplayListBuilder* aBuilder) {
+nsDisplayBackground::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) {
   nsRect r(nsPoint(0,0), mFrame->GetSize());
   nsPresContext* presContext = mFrame->PresContext();
 
   if (mIsThemed) {
     presContext->GetTheme()->
         GetWidgetOverflow(presContext->DeviceContext(), mFrame,
                           mFrame->GetStyleDisplay()->mAppearance, &r);
   }
 
-  return SnapBounds(mSnappingEnabled, presContext, r + ToReferenceFrame());
+  *aSnap = true;
+  return r + ToReferenceFrame();
 }
 
 nsRect
-nsDisplayOutline::GetBounds(nsDisplayListBuilder* aBuilder) {
+nsDisplayOutline::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) {
+  *aSnap = false;
   return mFrame->GetVisualOverflowRectRelativeToSelf() + ToReferenceFrame();
 }
 
 void
 nsDisplayOutline::Paint(nsDisplayListBuilder* aBuilder,
                         nsRenderingContext* aCtx) {
   // TODO join outlines together
   nsPoint offset = ToReferenceFrame();
@@ -1445,21 +1437,22 @@ nsDisplayBorder::Paint(nsDisplayListBuil
   nsCSSRendering::PaintBorder(mFrame->PresContext(), *aCtx, mFrame,
                               mVisibleRect,
                               nsRect(offset, mFrame->GetSize()),
                               mFrame->GetStyleContext(),
                               mFrame->GetSkipSides());
 }
 
 nsRect
-nsDisplayBorder::GetBounds(nsDisplayListBuilder* aBuilder)
+nsDisplayBorder::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap)
 {
   nsRect borderBounds(ToReferenceFrame(), mFrame->GetSize());
   borderBounds.Inflate(mFrame->GetStyleBorder()->GetImageOutset());
-  return SnapBounds(mSnappingEnabled, mFrame->PresContext(), borderBounds);
+  *aSnap = true;
+  return borderBounds;
 }
 
 // Given a region, compute a conservative approximation to it as a list
 // of rectangles that aren't vertically adjacent (i.e., vertically
 // adjacent or overlapping rectangles are combined).
 // Right now this is only approximate, some vertically overlapping rectangles
 // aren't guaranteed to be combined.
 static void
@@ -1502,17 +1495,18 @@ nsDisplayBoxShadowOuter::Paint(nsDisplay
     aCtx->IntersectClip(rects[i]);
     nsCSSRendering::PaintBoxShadowOuter(presContext, *aCtx, mFrame,
                                         borderRect, rects[i]);
     aCtx->PopState();
   }
 }
 
 nsRect
-nsDisplayBoxShadowOuter::GetBounds(nsDisplayListBuilder* aBuilder) {
+nsDisplayBoxShadowOuter::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) {
+  *aSnap = false;
   return mFrame->GetVisualOverflowRectRelativeToSelf() + ToReferenceFrame();
 }
 
 bool
 nsDisplayBoxShadowOuter::ComputeVisibility(nsDisplayListBuilder* aBuilder,
                                            nsRegion* aVisibleRegion,
                                            const nsRect& aAllowVisibleRegionExpansion) {
   if (!nsDisplayItem::ComputeVisibility(aBuilder, aVisibleRegion,
@@ -1594,38 +1588,39 @@ nsDisplayWrapList::~nsDisplayWrapList() 
 
 void
 nsDisplayWrapList::HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
                            HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames) {
   mList.HitTest(aBuilder, aRect, aState, aOutFrames);
 }
 
 nsRect
-nsDisplayWrapList::GetBounds(nsDisplayListBuilder* aBuilder) {
+nsDisplayWrapList::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) {
+  *aSnap = false;
   return mList.GetBounds(aBuilder);
 }
 
 bool
 nsDisplayWrapList::ComputeVisibility(nsDisplayListBuilder* aBuilder,
                                      nsRegion* aVisibleRegion,
                                      const nsRect& aAllowVisibleRegionExpansion) {
   return mList.ComputeVisibilityForSublist(aBuilder, aVisibleRegion,
                                            mVisibleRect,
                                            aAllowVisibleRegionExpansion);
 }
 
 nsRegion
 nsDisplayWrapList::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
+                                   bool* aSnap,
                                    bool* aForceTransparentSurface) {
-  if (aForceTransparentSurface) {
-    *aForceTransparentSurface = false;
-  }
+  *aForceTransparentSurface = false;
+  *aSnap = false;
   nsRegion result;
   if (mList.IsOpaque()) {
-    result = GetBounds(aBuilder);
+    result = GetBounds(aBuilder, aSnap);
   }
   return result;
 }
 
 bool nsDisplayWrapList::IsUniform(nsDisplayListBuilder* aBuilder, nscolor* aColor) {
   // We could try to do something but let's conservatively just return false.
   return false;
 }
@@ -1755,20 +1750,20 @@ nsDisplayOpacity::nsDisplayOpacity(nsDis
 
 #ifdef NS_BUILD_REFCNT_LOGGING
 nsDisplayOpacity::~nsDisplayOpacity() {
   MOZ_COUNT_DTOR(nsDisplayOpacity);
 }
 #endif
 
 nsRegion nsDisplayOpacity::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
+                                           bool* aSnap,
                                            bool* aForceTransparentSurface) {
-  if (aForceTransparentSurface) {
-    *aForceTransparentSurface = false;
-  }
+  *aForceTransparentSurface = false;
+  *aSnap = false;
   // We are never opaque, if our opacity was < 1 then we wouldn't have
   // been created.
   return nsRegion();
 }
 
 // nsDisplayOpacity uses layers for rendering
 already_AddRefed<Layer>
 nsDisplayOpacity::BuildLayer(nsDisplayListBuilder* aBuilder,
@@ -1815,17 +1810,18 @@ bool
 nsDisplayOpacity::ComputeVisibility(nsDisplayListBuilder* aBuilder,
                                     nsRegion* aVisibleRegion,
                                     const nsRect& aAllowVisibleRegionExpansion) {
   // Our children are translucent so we should not allow them to subtract
   // area from aVisibleRegion. We do need to find out what is visible under
   // our children in the temporary compositing buffer, because if our children
   // paint our entire bounds opaquely then we don't need an alpha channel in
   // the temporary compositing buffer.
-  nsRect bounds = GetBounds(aBuilder);
+  bool snap;
+  nsRect bounds = GetBounds(aBuilder, &snap);
   nsRegion visibleUnderChildren;
   visibleUnderChildren.And(*aVisibleRegion, bounds);
   nsRect allowExpansion;
   allowExpansion.IntersectRect(bounds, aAllowVisibleRegionExpansion);
   return
     nsDisplayWrapList::ComputeVisibility(aBuilder, &visibleUnderChildren,
                                          allowExpansion);
 }
@@ -2090,33 +2086,30 @@ nsDisplayScrollInfoLayer::ShouldFlattenA
   // nsDisplayScrollInfoLayer (with only the metadata) should survive the
   // visibility computation. 
   return RemoveScrollLayerCount() == 1;
 }
 
 nsDisplayClip::nsDisplayClip(nsDisplayListBuilder* aBuilder,
                              nsIFrame* aFrame, nsDisplayItem* aItem,
                              const nsRect& aRect)
-   : nsDisplayWrapList(aBuilder, aFrame, aItem) {
+   : nsDisplayWrapList(aBuilder, aFrame, aItem), mClip(aRect) {
   MOZ_COUNT_CTOR(nsDisplayClip);
-  mClip = SnapBounds(aBuilder->IsSnappingEnabled() && !aBuilder->IsInTransform(),
-                     aBuilder->CurrentPresContext(), aRect);
 }
 
 nsDisplayClip::nsDisplayClip(nsDisplayListBuilder* aBuilder,
                              nsIFrame* aFrame, nsDisplayList* aList,
                              const nsRect& aRect)
-   : nsDisplayWrapList(aBuilder, aFrame, aList) {
+   : nsDisplayWrapList(aBuilder, aFrame, aList), mClip(aRect) {
   MOZ_COUNT_CTOR(nsDisplayClip);
-  mClip = SnapBounds(aBuilder->IsSnappingEnabled() && !aBuilder->IsInTransform(),
-                     aBuilder->CurrentPresContext(), aRect);
 }
 
-nsRect nsDisplayClip::GetBounds(nsDisplayListBuilder* aBuilder) {
-  nsRect r = nsDisplayWrapList::GetBounds(aBuilder);
+nsRect nsDisplayClip::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) {
+  nsRect r = nsDisplayWrapList::GetBounds(aBuilder, aSnap);
+  *aSnap = true;
   r.IntersectRect(mClip, r);
   return r;
 }
 
 #ifdef NS_BUILD_REFCNT_LOGGING
 nsDisplayClip::~nsDisplayClip() {
   MOZ_COUNT_DTOR(nsDisplayClip);
 }
@@ -2188,21 +2181,21 @@ nsDisplayClipRoundedRect::nsDisplayClipR
 nsDisplayClipRoundedRect::~nsDisplayClipRoundedRect()
 {
   MOZ_COUNT_DTOR(nsDisplayClipRoundedRect);
 }
 #endif
 
 nsRegion
 nsDisplayClipRoundedRect::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
+                                          bool* aSnap,
                                           bool* aForceTransparentSurface)
 {
-  if (aForceTransparentSurface) {
-    *aForceTransparentSurface = false;
-  }
+  *aSnap = false;
+  *aForceTransparentSurface = false;
   return nsRegion();
 }
 
 void
 nsDisplayClipRoundedRect::HitTest(nsDisplayListBuilder* aBuilder,
                                   const nsRect& aRect, HitTestState* aState,
                                   nsTArray<nsIFrame*> *aOutFrames)
 {
@@ -2262,19 +2255,20 @@ nsDisplayZoom::nsDisplayZoom(nsDisplayLi
 }
 
 #ifdef NS_BUILD_REFCNT_LOGGING
 nsDisplayZoom::~nsDisplayZoom() {
   MOZ_COUNT_DTOR(nsDisplayZoom);
 }
 #endif
 
-nsRect nsDisplayZoom::GetBounds(nsDisplayListBuilder* aBuilder)
+nsRect nsDisplayZoom::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap)
 {
-  nsRect bounds = nsDisplayWrapList::GetBounds(aBuilder);
+  nsRect bounds = nsDisplayWrapList::GetBounds(aBuilder, aSnap);
+  *aSnap = false;
   return bounds.ConvertAppUnitsRoundOut(mAPD, mParentAPD);
 }
 
 void nsDisplayZoom::HitTest(nsDisplayListBuilder *aBuilder,
                             const nsRect& aRect,
                             HitTestState *aState,
                             nsTArray<nsIFrame*> *aOutFrames)
 {
@@ -2292,18 +2286,18 @@ void nsDisplayZoom::HitTest(nsDisplayLis
 
 void nsDisplayZoom::Paint(nsDisplayListBuilder* aBuilder,
                           nsRenderingContext* aCtx)
 {
   mList.PaintForFrame(aBuilder, aCtx, mFrame, nsDisplayList::PAINT_DEFAULT);
 }
 
 bool nsDisplayZoom::ComputeVisibility(nsDisplayListBuilder *aBuilder,
-                                        nsRegion *aVisibleRegion,
-                                        const nsRect& aAllowVisibleRegionExpansion)
+                                      nsRegion *aVisibleRegion,
+                                      const nsRect& aAllowVisibleRegionExpansion)
 {
   // Convert the passed in visible region to our appunits.
   nsRegion visibleRegion =
     aVisibleRegion->ConvertAppUnitsRoundOut(mParentAPD, mAPD);
   nsRegion originalVisibleRegion = visibleRegion;
 
   nsRect transformedVisibleRect =
     mVisibleRect.ConvertAppUnitsRoundOut(mParentAPD, mAPD);
@@ -2795,22 +2789,23 @@ nsDisplayTransform::GetHitDepthAtPoint(c
 
   gfxPoint3D transformed = matrix.Transform3D(gfxPoint3D(point.x, point.y, 0));
   return transformed.z;
 }
 
 /* The bounding rectangle for the object is the overflow rectangle translated
  * by the reference point.
  */
-nsRect nsDisplayTransform::GetBounds(nsDisplayListBuilder *aBuilder)
+nsRect nsDisplayTransform::GetBounds(nsDisplayListBuilder *aBuilder, bool* aSnap)
 {
   nsRect untransformedBounds =
     ShouldPrerenderTransformedContent(aBuilder, mFrame) ?
     mFrame->GetVisualOverflowRectRelativeToSelf() + ToReferenceFrame() :
-    mStoredList.GetBounds(aBuilder);
+    mStoredList.GetBounds(aBuilder, aSnap);
+  *aSnap = false;
   float factor = nsPresContext::AppUnitsPerCSSPixel();
   return nsLayoutUtils::MatrixTransformRect(untransformedBounds,
                                             GetTransform(factor),
                                             factor);
 }
 
 /* The transform is opaque iff the transform consists solely of scales and
  * translations and if the underlying content is opaque.  Thus if the transform
@@ -2824,34 +2819,37 @@ nsRect nsDisplayTransform::GetBounds(nsD
  *
  * We also need to check whether the underlying opaque content completely fills
  * our visible rect. We use UntransformRect which expands to the axis-aligned
  * bounding rect, but that's OK since if
  * mStoredList.GetVisibleRect().Contains(untransformedVisible), then it
  * certainly contains the actual (non-axis-aligned) untransformed rect.
  */
 nsRegion nsDisplayTransform::GetOpaqueRegion(nsDisplayListBuilder *aBuilder,
+                                             bool* aSnap,
                                              bool* aForceTransparentSurface)
 {
-  if (aForceTransparentSurface) {
-    *aForceTransparentSurface = false;
-  }
+  *aForceTransparentSurface = false;
+  *aSnap = false;
   nsRect untransformedVisible;
   float factor = nsPresContext::AppUnitsPerCSSPixel();
   if (!UntransformRectMatrix(mVisibleRect, GetTransform(factor), factor, &untransformedVisible)) {
       return nsRegion();
   }
   
   const gfx3DMatrix& matrix = GetTransform(nsPresContext::AppUnitsPerCSSPixel());
-                
+
   nsRegion result;
   gfxMatrix matrix2d;
+  bool tmpSnap;
+  bool forceTransparentSurface;
   if (matrix.Is2D(&matrix2d) &&
       matrix2d.PreservesAxisAlignedRectangles() &&
-      mStoredList.GetOpaqueRegion(aBuilder).Contains(untransformedVisible)) {
+      mStoredList.GetOpaqueRegion(aBuilder, &tmpSnap, &forceTransparentSurface).
+        Contains(untransformedVisible)) {
     result = mVisibleRect;
   }
   return result;
 }
 
 /* The transform is uniform if it fills the entire bounding rect and the
  * wrapped list is uniform.  See GetOpaqueRegion for discussion of why this
  * works.
@@ -3002,21 +3000,21 @@ nsDisplaySVGEffects::nsDisplaySVGEffects
 #ifdef NS_BUILD_REFCNT_LOGGING
 nsDisplaySVGEffects::~nsDisplaySVGEffects()
 {
   MOZ_COUNT_DTOR(nsDisplaySVGEffects);
 }
 #endif
 
 nsRegion nsDisplaySVGEffects::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
+                                              bool* aSnap,
                                               bool* aForceTransparentSurface)
 {
-  if (aForceTransparentSurface) {
-    *aForceTransparentSurface = false;
-  }
+  *aForceTransparentSurface = false;
+  *aSnap = false;
   return nsRegion();
 }
 
 void
 nsDisplaySVGEffects::HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
                              HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames)
 {
   nsPoint rectCenter(aRect.x + aRect.width / 2, aRect.y + aRect.height / 2);
--- a/layout/base/nsDisplayList.h
+++ b/layout/base/nsDisplayList.h
@@ -302,26 +302,16 @@ public:
    * Call this if ReferenceFrame() is a viewport frame with fixed-position
    * children, or when we construct an item which will return true from
    * ShouldFixToViewport()
    */
   void SetHasFixedItems() { mHasFixedItems = true; }
   bool GetHasFixedItems() { return mHasFixedItems; }
 
   /**
-   * Returns true if snapping is enabled for the final drawing context.
-   * The default is true.
-   */
-  bool IsSnappingEnabled() { return mSnappingEnabled; }
-  /**
-   * Set if snapping is enabled for the final drawing context.
-   */
-  void SetSnappingEnabled(bool aSnappingEnabled) { mSnappingEnabled = aSnappingEnabled; }
-
-  /**
    * @return true if images have been set to decode synchronously.
    */
   bool ShouldSyncDecodeImages() { return mSyncDecodeImages; }
 
   /**
    * Indicates whether we should synchronously decode images. If true, we decode
    * and draw whatever image data has been loaded. If false, we just draw
    * whatever has already been decoded.
@@ -515,17 +505,16 @@ private:
   bool                           mIncludeAllOutOfFlows;
   bool                           mSelectedFramesOnly;
   bool                           mAccurateVisibleRegions;
   // True when we're building a display list that's directly or indirectly
   // under an nsDisplayTransform
   bool                           mInTransform;
   bool                           mSyncDecodeImages;
   bool                           mIsPaintingToWindow;
-  bool                           mSnappingEnabled;
   bool                           mHasDisplayPort;
   bool                           mHasFixedItems;
 };
 
 class nsDisplayItem;
 class nsDisplayList;
 /**
  * nsDisplayItems are put in singly-linked lists rooted in an nsDisplayList.
@@ -641,34 +630,43 @@ public:
    * @return the frame that this display item is based on. This is used to sort
    * items by z-index and content order and for some other uses. For some items
    * that wrap item lists, this could return nsnull because there is no single
    * underlying frame; for leaf items it will never return nsnull.
    */
   inline nsIFrame* GetUnderlyingFrame() const { return mFrame; }
   /**
    * The default bounds is the frame border rect.
+   * @param aSnap *aSnap is set to true if the returned rect will be
+   * snapped to nearest device pixel edges during actual drawing.
+   * It might be set to false and snap anyway, so code computing the set of
+   * pixels affected by this display item needs to round outwards to pixel
+   * boundaries when *aSnap is set to false.
    * @return a rectangle relative to aBuilder->ReferenceFrame() that
    * contains the area drawn by this display item
    */
-  virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder) {
+  virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap)
+  {
+    *aSnap = false;
     return nsRect(ToReferenceFrame(), GetUnderlyingFrame()->GetSize());
   }
   /**
+   * @param aSnap set to true if the edges of the rectangles of the opaque
+   * region would be snapped to device pixels when drawing
    * @return a region of the item that is opaque --- every pixel painted
    * with an opaque color. This is useful for determining when one piece
    * of content completely obscures another so that we can do occlusion
    * culling.
    */
   virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
-                                   bool* aForceTransparentSurface = nsnull)
+                                   bool* aSnap,
+                                   bool* aForceTransparentSurface)
   {
-    if (aForceTransparentSurface) {
-      *aForceTransparentSurface = false;
-    }
+    *aSnap = false;
+    *aForceTransparentSurface = false;
     return nsRegion();
   }
   /**
    * If this returns true, then aColor is set to the uniform color
    * @return true if the item is guaranteed to paint every pixel in its
    * bounds with the same (possibly translucent) color
    */
   virtual bool IsUniform(nsDisplayListBuilder* aBuilder, nscolor* aColor) { return false; }
@@ -1327,18 +1325,20 @@ public:
 #endif
   
   virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) {
     mPaint(mFrame, aCtx, mVisibleRect, ToReferenceFrame());
   }
   NS_DISPLAY_DECL_NAME(mName, mType)
 
   virtual nsRect GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder) {
-    if (mType == nsDisplayItem::TYPE_HEADER_FOOTER)
-      return GetBounds(aBuilder);
+    if (mType == nsDisplayItem::TYPE_HEADER_FOOTER) {
+      bool snap;
+      return GetBounds(aBuilder, &snap);
+    }
     return nsRect();
   }
 
 protected:
   PaintCallback mPaint;
 #ifdef MOZ_DUMP_PAINTING
   const char*   mName;
 #endif
@@ -1436,51 +1436,49 @@ public:
     MOZ_COUNT_CTOR(nsDisplayCaret);
   }
 #ifdef NS_BUILD_REFCNT_LOGGING
   virtual ~nsDisplayCaret() {
     MOZ_COUNT_DTOR(nsDisplayCaret);
   }
 #endif
 
-  virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder) {
+  virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) {
+    *aSnap = false;
     // The caret returns a rect in the coordinates of mFrame.
     return mCaret->GetCaretRect() + ToReferenceFrame();
   }
   virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx);
   NS_DISPLAY_DECL_NAME("Caret", TYPE_CARET)
 protected:
   nsRefPtr<nsCaret> mCaret;
 };
 
 /**
  * The standard display item to paint the CSS borders of a frame.
  */
 class nsDisplayBorder : public nsDisplayItem {
 public:
   nsDisplayBorder(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame) :
-    nsDisplayItem(aBuilder, aFrame),
-    mSnappingEnabled(aBuilder->IsSnappingEnabled() && !aBuilder->IsInTransform()) {
+    nsDisplayItem(aBuilder, aFrame)
+  {
     MOZ_COUNT_CTOR(nsDisplayBorder);
   }
 #ifdef NS_BUILD_REFCNT_LOGGING
   virtual ~nsDisplayBorder() {
     MOZ_COUNT_DTOR(nsDisplayBorder);
   }
 #endif
 
-  virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder);
+  virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap);
   virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx);
   virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
                                    nsRegion* aVisibleRegion,
                                    const nsRect& aAllowVisibleRegionExpansion);
   NS_DISPLAY_DECL_NAME("Border", TYPE_BORDER)
-
-protected:
-  bool mSnappingEnabled;
 };
 
 /**
  * A simple display item that just renders a solid color across the
  * specified bounds. For canvas frames (in the CSS sense) we split off the
  * drawing of the background color into this class (from nsDisplayBackground
  * via nsDisplayCanvasBackground). This is done so that we can always draw a
  * background color to avoid ugly flashes of white when we can't draw a full
@@ -1488,37 +1486,37 @@ protected:
  * frame's bounds -- this is needed when a frame/iframe is loading and there
  * is not yet a frame tree to go in the frame/iframe so we use the subdoc
  * frame of the parent document as a standin.
  */
 class nsDisplaySolidColor : public nsDisplayItem {
 public:
   nsDisplaySolidColor(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
                       const nsRect& aBounds, nscolor aColor)
-    : nsDisplayItem(aBuilder, aFrame), mBounds(aBounds), mColor(aColor),
-      mSnappingEnabled(aBuilder->IsSnappingEnabled() && !aBuilder->IsInTransform()) {
+    : nsDisplayItem(aBuilder, aFrame), mBounds(aBounds), mColor(aColor)
+  {
     NS_ASSERTION(NS_GET_A(aColor) > 0, "Don't create invisible nsDisplaySolidColors!");
     MOZ_COUNT_CTOR(nsDisplaySolidColor);
   }
 #ifdef NS_BUILD_REFCNT_LOGGING
   virtual ~nsDisplaySolidColor() {
     MOZ_COUNT_DTOR(nsDisplaySolidColor);
   }
 #endif
 
-  virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder);
+  virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap);
 
   virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
-                                   bool* aOutTransparentBackground = nsnull) {
-    if (aOutTransparentBackground) {
-      *aOutTransparentBackground = false;
-    }
+                                   bool* aSnap,
+                                   bool* aOutTransparentBackground) {
+    *aSnap = false;
+    *aOutTransparentBackground = false;
     nsRegion result;
     if (NS_GET_A(mColor) == 255) {
-      result = GetBounds(aBuilder);
+      result = GetBounds(aBuilder, aSnap);
     }
     return result;
   }
 
   virtual bool IsUniform(nsDisplayListBuilder* aBuilder, nscolor* aColor)
   {
     *aColor = mColor;
     return true;
@@ -1526,17 +1524,16 @@ public:
 
   virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx);
 
   NS_DISPLAY_DECL_NAME("SolidColor", TYPE_SOLID_COLOR)
 
 private:
   nsRect  mBounds;
   nscolor mColor;
-  bool mSnappingEnabled;
 };
 
 /**
  * The standard display item to paint the CSS background of a frame.
  */
 class nsDisplayBackground : public nsDisplayItem {
 public:
   nsDisplayBackground(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame);
@@ -1547,31 +1544,31 @@ public:
 #endif
 
   virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
                        HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames);
   virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
                                    nsRegion* aVisibleRegion,
                                    const nsRect& aAllowVisibleRegionExpansion);
   virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
-                                   bool* aForceTransparentSurface = nsnull);
+                                   bool* aSnap,
+                                   bool* aForceTransparentSurface);
   virtual bool IsVaryingRelativeToMovingFrame(nsDisplayListBuilder* aBuilder,
                                                 nsIFrame* aFrame);
   virtual bool IsUniform(nsDisplayListBuilder* aBuilder, nscolor* aColor);
   virtual bool ShouldFixToViewport(nsDisplayListBuilder* aBuilder);
-  virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder);
+  virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap);
   virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx);
   NS_DISPLAY_DECL_NAME("Background", TYPE_BACKGROUND)
 protected:
   nsRegion GetInsideClipRegion(nsPresContext* aPresContext, PRUint8 aClip,
-                               const nsRect& aRect);
+                               const nsRect& aRect, bool* aSnap);
 
   /* Used to cache mFrame->IsThemed() since it isn't a cheap call */
   bool mIsThemed;
-  bool mSnappingEnabled;
   nsITheme::Transparency mThemeTransparency;
 };
 
 /**
  * The standard display item to paint the outer CSS box-shadows of a frame.
  */
 class nsDisplayBoxShadowOuter : public nsDisplayItem {
 public:
@@ -1581,17 +1578,17 @@ public:
   }
 #ifdef NS_BUILD_REFCNT_LOGGING
   virtual ~nsDisplayBoxShadowOuter() {
     MOZ_COUNT_DTOR(nsDisplayBoxShadowOuter);
   }
 #endif
 
   virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx);
-  virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder);
+  virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap);
   virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
                                    nsRegion* aVisibleRegion,
                                    const nsRect& aAllowVisibleRegionExpansion);
   NS_DISPLAY_DECL_NAME("BoxShadowOuter", TYPE_BOX_SHADOW_OUTER)
 
 private:
   nsRegion mVisibleRegion;
 };
@@ -1631,17 +1628,17 @@ public:
     MOZ_COUNT_CTOR(nsDisplayOutline);
   }
 #ifdef NS_BUILD_REFCNT_LOGGING
   virtual ~nsDisplayOutline() {
     MOZ_COUNT_DTOR(nsDisplayOutline);
   }
 #endif
 
-  virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder);
+  virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap);
   virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx);
   virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
                                    nsRegion* aVisibleRegion,
                                    const nsRect& aAllowVisibleRegionExpansion);
   NS_DISPLAY_DECL_NAME("Outline", TYPE_OUTLINE)
 };
 
 /**
@@ -1689,19 +1686,20 @@ public:
   nsDisplayWrapList(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
                     nsDisplayList* aList);
   nsDisplayWrapList(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
                     nsDisplayItem* aItem);
   nsDisplayWrapList(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame);
   virtual ~nsDisplayWrapList();
   virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
                        HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames);
-  virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder);
+  virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap);
   virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
-                                   bool* aForceTransparentSurface = nsnull);
+                                   bool* aSnap,
+                                   bool* aForceTransparentSurface);
   virtual bool IsUniform(nsDisplayListBuilder* aBuilder, nscolor* aColor);
   virtual bool IsVaryingRelativeToMovingFrame(nsDisplayListBuilder* aBuilder,
                                                 nsIFrame* aFrame);
   virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx);
   virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
                                    nsRegion* aVisibleRegion,
                                    const nsRect& aAllowVisibleRegionExpansion);
   virtual bool TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem) {
@@ -1776,17 +1774,18 @@ class nsDisplayOpacity : public nsDispla
 public:
   nsDisplayOpacity(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
                    nsDisplayList* aList);
 #ifdef NS_BUILD_REFCNT_LOGGING
   virtual ~nsDisplayOpacity();
 #endif
   
   virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
-                                   bool* aForceTransparentSurface = nsnull);
+                                   bool* aSnap,
+                                   bool* aForceTransparentSurface);
   virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
                                              LayerManager* aManager,
                                              const ContainerParameters& aContainerParameters);
   virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
                                    LayerManager* aManager);
   virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
                                    nsRegion* aVisibleRegion,
                                    const nsRect& aAllowVisibleRegionExpansion);  
@@ -1941,17 +1940,17 @@ public:
   nsDisplayClip(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
                 nsDisplayItem* aItem, const nsRect& aRect);
   nsDisplayClip(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
                 nsDisplayList* aList, const nsRect& aRect);
 #ifdef NS_BUILD_REFCNT_LOGGING
   virtual ~nsDisplayClip();
 #endif
   
-  virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder);
+  virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap);
   virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx);
   virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
                                    nsRegion* aVisibleRegion,
                                    const nsRect& aAllowVisibleRegionExpansion);
   virtual bool TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem);
   NS_DISPLAY_DECL_NAME("Clip", TYPE_CLIP)
   virtual PRUint32 GetPerFrameKey() { return 0; }
   
@@ -1982,17 +1981,18 @@ public:
   nsDisplayClipRoundedRect(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
                            nsDisplayList* aList,
                            const nsRect& aRect, nscoord aRadii[8]);
 #ifdef NS_BUILD_REFCNT_LOGGING
   virtual ~nsDisplayClipRoundedRect();
 #endif
 
   virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
-                                   bool* aForceTransparentSurface = nsnull);
+                                   bool* aSnap,
+                                   bool* aForceTransparentSurface);
   virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
                        HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames);
   virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
                                    nsRegion* aVisibleRegion,
                                    const nsRect& aAllowVisibleRegionExpansion);
   virtual bool TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem);
   NS_DISPLAY_DECL_NAME("ClipRoundedRect", TYPE_CLIP_ROUNDED_RECT)
 
@@ -2022,17 +2022,17 @@ public:
    */
   nsDisplayZoom(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
                 nsDisplayList* aList,
                 PRInt32 aAPD, PRInt32 aParentAPD);
 #ifdef NS_BUILD_REFCNT_LOGGING
   virtual ~nsDisplayZoom();
 #endif
   
-  virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder);
+  virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap);
   virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx);
   virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
                        HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames);
   virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
                                    nsRegion* aVisibleRegion,
                                    const nsRect& aAllowVisibleRegionExpansion);
   NS_DISPLAY_DECL_NAME("Zoom", TYPE_ZOOM)
 
@@ -2053,20 +2053,22 @@ class nsDisplaySVGEffects : public nsDis
 public:
   nsDisplaySVGEffects(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
                       nsDisplayList* aList);
 #ifdef NS_BUILD_REFCNT_LOGGING
   virtual ~nsDisplaySVGEffects();
 #endif
   
   virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
-                                   bool* aForceTransparentSurface = nsnull);
+                                   bool* aSnap,
+                                   bool* aForceTransparentSurface);
   virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
                        HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames);
-  virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder) {
+  virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) {
+    *aSnap = false;
     return mBounds + aBuilder->ToReferenceFrame(mEffectsFrame);
   }
   virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx);
   virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
                                    nsRegion* aVisibleRegion,
                                    const nsRect& aAllowVisibleRegionExpansion);  
   virtual bool TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem);
   NS_DISPLAY_DECL_NAME("SVGEffects", TYPE_SVG_EFFECTS)
@@ -2125,26 +2127,28 @@ public:
 #endif
 
   NS_DISPLAY_DECL_NAME("nsDisplayTransform", TYPE_TRANSFORM);
 
   virtual nsRect GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder)
   {
     if (mStoredList.GetComponentAlphaBounds(aBuilder).IsEmpty())
       return nsRect();
-    return GetBounds(aBuilder);
+    bool snap;
+    return GetBounds(aBuilder, &snap);
   }
 
   nsDisplayWrapList* GetStoredList() { return &mStoredList; }
 
   virtual void HitTest(nsDisplayListBuilder *aBuilder, const nsRect& aRect,
                        HitTestState *aState, nsTArray<nsIFrame*> *aOutFrames);
-  virtual nsRect GetBounds(nsDisplayListBuilder *aBuilder);
+  virtual nsRect GetBounds(nsDisplayListBuilder *aBuilder, bool* aSnap);
   virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder *aBuilder,
-                                   bool* aForceTransparentSurface = nsnull);
+                                   bool* aSnap,
+                                   bool* aForceTransparentSurface);
   virtual bool IsUniform(nsDisplayListBuilder *aBuilder, nscolor* aColor);
   virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
                                    LayerManager* aManager);
   virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
                                              LayerManager* aManager,
                                              const ContainerParameters& aContainerParameters);
   virtual bool ComputeVisibility(nsDisplayListBuilder *aBuilder,
                                    nsRegion *aVisibleRegion,
--- a/layout/base/nsLayoutDebugger.cpp
+++ b/layout/base/nsLayoutDebugger.cpp
@@ -165,17 +165,18 @@ PrintDisplayListTo(nsDisplayListBuilder*
     fprintf(aOutput, "<li>");
     nsIFrame* f = i->GetUnderlyingFrame();
     nsAutoString fName;
 #ifdef DEBUG
     if (f) {
       f->GetFrameName(fName);
     }
 #endif
-    nsRect rect = i->GetBounds(aBuilder);
+    bool snap;
+    nsRect rect = i->GetBounds(aBuilder, &snap);
     switch (i->GetType()) {
       case nsDisplayItem::TYPE_CLIP:
       case nsDisplayItem::TYPE_CLIP_ROUNDED_RECT: {
         nsDisplayClip* c = static_cast<nsDisplayClip*>(i);
         rect = c->GetClipRect();
         break;
       }
       default:
@@ -186,17 +187,18 @@ PrintDisplayListTo(nsDisplayListBuilder*
     nsDisplayList* list = i->GetList();
     nsRegion opaque;
     if (i->GetType() == nsDisplayItem::TYPE_TRANSFORM) {
         nsDisplayTransform* t = static_cast<nsDisplayTransform*>(i);
         list = t->GetStoredList()->GetList();
     }
 #ifdef DEBUG
     if (!list || list->DidComputeVisibility()) {
-      opaque = i->GetOpaqueRegion(aBuilder);
+      bool forceTransparentSurface;
+      opaque = i->GetOpaqueRegion(aBuilder, &snap, &forceTransparentSurface);
     }
 #endif
     if (i->Painted()) {
       nsCString string(i->Name());
       string.Append("-");
       string.AppendInt((PRUint64)i);
       fprintf(aOutput, "<a href=\"javascript:ViewImage('%s')\">", string.BeginReading());
     }
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -1602,20 +1602,16 @@ nsLayoutUtils::PaintFrame(nsRenderingCon
     builder.SetSyncDecodeImages(true);
   }
   if (aFlags & (PAINT_WIDGET_LAYERS | PAINT_TO_WINDOW)) {
     builder.SetPaintingToWindow(true);
   }
   if (aFlags & PAINT_IGNORE_SUPPRESSION) {
     builder.IgnorePaintSuppression();
   }
-  if (aRenderingContext &&
-      aRenderingContext->ThebesContext()->GetFlags() & gfxContext::FLAG_DISABLE_SNAPPING) {
-    builder.SetSnappingEnabled(false);
-  }
   nsRect canvasArea(nsPoint(0, 0), aFrame->GetSize());
 
 #ifdef DEBUG
   if (ignoreViewportScrolling) {
     nsIDocument* doc = aFrame->GetContent() ?
       aFrame->GetContent()->GetCurrentDoc() : nsnull;
     NS_ASSERTION(!aFrame->GetParent() ||
                  (doc && doc->IsBeingUsedAsImage()),
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -4598,17 +4598,18 @@ PresShell::ClipListToRange(nsDisplayList
         else if (content->GetCurrentDoc() ==
                    aRange->GetStartParent()->GetCurrentDoc()) {
           // if the node is within the range, append it to the temporary list
           bool before, after;
           nsresult rv =
             nsRange::CompareNodeToRange(content, aRange, &before, &after);
           if (NS_SUCCEEDED(rv) && !before && !after) {
             itemToInsert = i;
-            surfaceRect.UnionRect(surfaceRect, i->GetBounds(aBuilder));
+            bool snap;
+            surfaceRect.UnionRect(surfaceRect, i->GetBounds(aBuilder, &snap));
           }
         }
       }
     }
 
     // insert the item into the list if necessary. If the item has a child
     // list, insert that as well
     nsDisplayList* sublist = i->GetList();
--- a/layout/forms/nsButtonFrameRenderer.cpp
+++ b/layout/forms/nsButtonFrameRenderer.cpp
@@ -101,24 +101,25 @@ public:
 #ifdef NS_BUILD_REFCNT_LOGGING
   virtual ~nsDisplayButtonBoxShadowOuter() {
     MOZ_COUNT_DTOR(nsDisplayButtonBoxShadowOuter);
   }
 #endif  
   
   virtual void Paint(nsDisplayListBuilder* aBuilder,
                      nsRenderingContext* aCtx);
-  virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder);
+  virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap);
   NS_DISPLAY_DECL_NAME("ButtonBoxShadowOuter", TYPE_BUTTON_BOX_SHADOW_OUTER)
 private:
   nsButtonFrameRenderer* mBFR;
 };
 
 nsRect
-nsDisplayButtonBoxShadowOuter::GetBounds(nsDisplayListBuilder* aBuilder) {
+nsDisplayButtonBoxShadowOuter::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) {
+  *aSnap = false;
   return mFrame->GetVisualOverflowRectRelativeToSelf() + ToReferenceFrame();
 }
 
 void
 nsDisplayButtonBoxShadowOuter::Paint(nsDisplayListBuilder* aBuilder,
                                      nsRenderingContext* aCtx) {
   nsRect frameRect = nsRect(ToReferenceFrame(), mFrame->GetSize());
 
--- a/layout/forms/nsSelectsAreaFrame.cpp
+++ b/layout/forms/nsSelectsAreaFrame.cpp
@@ -144,17 +144,18 @@ public:
     MOZ_COUNT_CTOR(nsDisplayListFocus);
   }
 #ifdef NS_BUILD_REFCNT_LOGGING
   virtual ~nsDisplayListFocus() {
     MOZ_COUNT_DTOR(nsDisplayListFocus);
   }
 #endif
 
-  virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder) {
+  virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) {
+    *aSnap = false;
     // override bounds because the list item focus ring may extend outside
     // the nsSelectsAreaFrame
     nsListControlFrame* listFrame = GetEnclosingListFrame(GetUnderlyingFrame());
     return listFrame->GetVisualOverflowRectRelativeToSelf() +
            aBuilder->ToReferenceFrame(listFrame);
   }
   virtual void Paint(nsDisplayListBuilder* aBuilder,
                      nsRenderingContext* aCtx) {
--- a/layout/generic/TextOverflow.cpp
+++ b/layout/generic/TextOverflow.cpp
@@ -185,17 +185,18 @@ public:
       mAscent(aAscent), mIndex(aIndex) {
     MOZ_COUNT_CTOR(nsDisplayTextOverflowMarker);
   }
 #ifdef NS_BUILD_REFCNT_LOGGING
   virtual ~nsDisplayTextOverflowMarker() {
     MOZ_COUNT_DTOR(nsDisplayTextOverflowMarker);
   }
 #endif
-  virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder) {
+  virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) {
+    *aSnap = false;
     nsRect shadowRect =
       nsLayoutUtils::GetTextShadowRectsUnion(mRect, mFrame);
     return mRect.Union(shadowRect);
   }
   virtual void Paint(nsDisplayListBuilder* aBuilder,
                      nsRenderingContext* aCtx);
 
   virtual PRUint32 GetPerFrameKey() { 
--- a/layout/generic/nsBulletFrame.cpp
+++ b/layout/generic/nsBulletFrame.cpp
@@ -208,31 +208,33 @@ public:
     MOZ_COUNT_CTOR(nsDisplayBullet);
   }
 #ifdef NS_BUILD_REFCNT_LOGGING
   virtual ~nsDisplayBullet() {
     MOZ_COUNT_DTOR(nsDisplayBullet);
   }
 #endif
 
-  virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder)
+  virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap)
   {
+    *aSnap = false;
     return mFrame->GetVisualOverflowRectRelativeToSelf() + ToReferenceFrame();
   }
   virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
                        HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames) {
     aOutFrames->AppendElement(mFrame);
   }
   virtual void Paint(nsDisplayListBuilder* aBuilder,
                      nsRenderingContext* aCtx);
   NS_DISPLAY_DECL_NAME("Bullet", TYPE_BULLET)
 
   virtual nsRect GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder)
   {
-    return GetBounds(aBuilder);
+    bool snap;
+    return GetBounds(aBuilder, &snap);
   }
 };
 
 void nsDisplayBullet::Paint(nsDisplayListBuilder* aBuilder,
                             nsRenderingContext* aCtx)
 {
   static_cast<nsBulletFrame*>(mFrame)->
     PaintBullet(*aCtx, ToReferenceFrame(), mVisibleRect);
--- a/layout/generic/nsCanvasFrame.cpp
+++ b/layout/generic/nsCanvasFrame.cpp
@@ -248,18 +248,19 @@ public:
     : nsDisplayItem(aBuilder, aFrame)
   {
     MOZ_COUNT_CTOR(nsDisplayCanvasFocus);
   }
   virtual ~nsDisplayCanvasFocus() {
     MOZ_COUNT_DTOR(nsDisplayCanvasFocus);
   }
 
-  virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder)
+  virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap)
   {
+    *aSnap = false;
     // This is an overestimate, but that's not a problem.
     nsCanvasFrame* frame = static_cast<nsCanvasFrame*>(mFrame);
     return frame->CanvasArea() + ToReferenceFrame();
   }
 
   virtual void Paint(nsDisplayListBuilder* aBuilder,
                      nsRenderingContext* aCtx)
   {
--- a/layout/generic/nsCanvasFrame.h
+++ b/layout/generic/nsCanvasFrame.h
@@ -157,53 +157,50 @@ class nsDisplayCanvasBackground : public
 public:
   nsDisplayCanvasBackground(nsDisplayListBuilder* aBuilder, nsIFrame *aFrame)
     : nsDisplayBackground(aBuilder, aFrame)
   {
     mExtraBackgroundColor = NS_RGBA(0,0,0,0);
   }
 
   virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
-                                   nsRegion* aVisibleRegion,
-                                   const nsRect& aAllowVisibleRegionExpansion)
+                                 nsRegion* aVisibleRegion,
+                                 const nsRect& aAllowVisibleRegionExpansion)
   {
     return NS_GET_A(mExtraBackgroundColor) > 0 ||
       nsDisplayBackground::ComputeVisibility(aBuilder, aVisibleRegion,
                                              aAllowVisibleRegionExpansion);
   }
   virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
-                                   bool* aForceTransparentSurface = nsnull)
+                                   bool* aSnap,
+                                   bool* aForceTransparentSurface)
   {
-    if (aForceTransparentSurface) {
+    if (NS_GET_A(mExtraBackgroundColor) == 255) {
       *aForceTransparentSurface = false;
+      return nsRegion(GetBounds(aBuilder, aSnap));
     }
-    if (NS_GET_A(mExtraBackgroundColor) == 255)
-      return nsRegion(GetBounds(aBuilder));
-    return nsDisplayBackground::GetOpaqueRegion(aBuilder);
+    return nsDisplayBackground::GetOpaqueRegion(aBuilder, aSnap,
+                                                aForceTransparentSurface);
   }
   virtual bool IsUniform(nsDisplayListBuilder* aBuilder, nscolor* aColor)
   {
     nscolor background;
     if (!nsDisplayBackground::IsUniform(aBuilder, &background))
       return false;
     NS_ASSERTION(background == NS_RGBA(0,0,0,0),
                  "The nsDisplayBackground for a canvas frame doesn't paint "
                  "its background color normally");
     *aColor = mExtraBackgroundColor;
     return true;
   }
-  virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder)
+  virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap)
   {
     nsCanvasFrame* frame = static_cast<nsCanvasFrame*>(mFrame);
-    nsRect r = frame->CanvasArea() + ToReferenceFrame();
-    if (mSnappingEnabled) {
-      nscoord appUnitsPerDevPixel = frame->PresContext()->AppUnitsPerDevPixel();
-      r = r.ToNearestPixels(appUnitsPerDevPixel).ToAppUnits(appUnitsPerDevPixel);
-    }
-    return r;
+    *aSnap = true;
+    return frame->CanvasArea() + ToReferenceFrame();
   }
   virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
                        HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames)
   {
     // We need to override so we don't consider border-radius.
     aOutFrames->AppendElement(mFrame);
   }
 
--- a/layout/generic/nsHTMLCanvasFrame.cpp
+++ b/layout/generic/nsHTMLCanvasFrame.cpp
@@ -77,30 +77,31 @@ public:
   virtual ~nsDisplayCanvas() {
     MOZ_COUNT_DTOR(nsDisplayCanvas);
   }
 #endif
 
   NS_DISPLAY_DECL_NAME("nsDisplayCanvas", TYPE_CANVAS)
 
   virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
-                                   bool* aForceTransparentSurface = nsnull) {
-    if (aForceTransparentSurface) {
-      *aForceTransparentSurface = false;
-    }
+                                   bool* aSnap,
+                                   bool* aForceTransparentSurface) {
+    *aForceTransparentSurface = false;
+    *aSnap = false;
     nsIFrame* f = GetUnderlyingFrame();
     nsHTMLCanvasElement *canvas = CanvasElementFromContent(f->GetContent());
     nsRegion result;
     if (canvas->GetIsOpaque()) {
-      result = GetBounds(aBuilder);
+      result = GetBounds(aBuilder, aSnap);
     }
     return result;
   }
 
-  virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder) {
+  virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) {
+    *aSnap = false;
     nsHTMLCanvasFrame* f = static_cast<nsHTMLCanvasFrame*>(GetUnderlyingFrame());
     return f->GetInnerArea() + ToReferenceFrame();
   }
 
   virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
                                              LayerManager* aManager,
                                              const ContainerParameters& aContainerParameters)
   {
--- a/layout/generic/nsObjectFrame.cpp
+++ b/layout/generic/nsObjectFrame.cpp
@@ -912,17 +912,17 @@ public:
     MOZ_COUNT_CTOR(nsDisplayPluginReadback);
   }
 #ifdef NS_BUILD_REFCNT_LOGGING
   virtual ~nsDisplayPluginReadback() {
     MOZ_COUNT_DTOR(nsDisplayPluginReadback);
   }
 #endif
 
-  virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder);
+  virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap);
   virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
                                    nsRegion* aVisibleRegion,
                                    const nsRect& aAllowVisibleRegionExpansion);
 
   NS_DISPLAY_DECL_NAME("PluginReadback", TYPE_PLUGIN_READBACK)
 
   virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
                                              LayerManager* aManager,
@@ -941,70 +941,75 @@ public:
 static nsRect
 GetDisplayItemBounds(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem, nsIFrame* aFrame)
 {
   // XXX For slightly more accurate region computations we should pixel-snap this
   return aFrame->GetContentRectRelativeToSelf() + aItem->ToReferenceFrame();
 }
 
 nsRect
-nsDisplayPluginReadback::GetBounds(nsDisplayListBuilder* aBuilder)
+nsDisplayPluginReadback::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap)
 {
+  *aSnap = false;
   return GetDisplayItemBounds(aBuilder, this, mFrame);
 }
 
 bool
 nsDisplayPluginReadback::ComputeVisibility(nsDisplayListBuilder* aBuilder,
                                            nsRegion* aVisibleRegion,
                                            const nsRect& aAllowVisibleRegionExpansion)
 {
   if (!nsDisplayItem::ComputeVisibility(aBuilder, aVisibleRegion,
                                         aAllowVisibleRegionExpansion))
     return false;
 
   nsRect expand;
-  expand.IntersectRect(aAllowVisibleRegionExpansion, GetBounds(aBuilder));
+  bool snap;
+  expand.IntersectRect(aAllowVisibleRegionExpansion, GetBounds(aBuilder, &snap));
   // *Add* our bounds to the visible region so that stuff underneath us is
   // likely to be made visible, so we can use it for a background! This is
   // a bit crazy since we normally only subtract from the visible region.
   aVisibleRegion->Or(*aVisibleRegion, expand);
   return true;
 }
 
 nsRect
-nsDisplayPlugin::GetBounds(nsDisplayListBuilder* aBuilder)
+nsDisplayPlugin::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap)
 {
+  *aSnap = false;
   return GetDisplayItemBounds(aBuilder, this, mFrame);
 }
 
 void
 nsDisplayPlugin::Paint(nsDisplayListBuilder* aBuilder,
                        nsRenderingContext* aCtx)
 {
   nsObjectFrame* f = static_cast<nsObjectFrame*>(mFrame);
-  f->PaintPlugin(aBuilder, *aCtx, mVisibleRect, GetBounds(aBuilder));
+  bool snap;
+  f->PaintPlugin(aBuilder, *aCtx, mVisibleRect, GetBounds(aBuilder, &snap));
 }
 
 bool
 nsDisplayPlugin::ComputeVisibility(nsDisplayListBuilder* aBuilder,
                                    nsRegion* aVisibleRegion,
                                    const nsRect& aAllowVisibleRegionExpansion)
 {
-  mVisibleRegion.And(*aVisibleRegion, GetBounds(aBuilder));  
+  bool snap;
+  mVisibleRegion.And(*aVisibleRegion, GetBounds(aBuilder, &snap));
   return nsDisplayItem::ComputeVisibility(aBuilder, aVisibleRegion,
                                           aAllowVisibleRegionExpansion);
 }
 
 nsRegion
 nsDisplayPlugin::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
+                                 bool* aSnap,
                                  bool* aForceTransparentSurface)
 {
-  if (aForceTransparentSurface) {
-    *aForceTransparentSurface = false;
-  }
+  *aForceTransparentSurface = false;
+  *aSnap = false;
   nsRegion result;
   nsObjectFrame* f = static_cast<nsObjectFrame*>(mFrame);
   if (!aBuilder->IsForPluginGeometry()) {
     nsIWidget* widget = f->GetWidget();
     if (widget) {
       nsTArray<nsIntRect> clip;
       widget->GetWindowClipRegion(&clip);
       nsTArray<nsIWidget::Configuration> configuration;
@@ -1013,21 +1018,23 @@ nsDisplayPlugin::GetOpaqueRegion(nsDispl
       if (clip != configuration[0].mClipRegion) {
         // Something has clipped us unexpectedly. Perhaps there is a translucent
         // chrome element overlaying us that forced us to be clipped away. Treat
         // us as non-opaque since we may have holes.
     	return result;
       }
     }
   }
-  if (f->IsOpaque() &&
-      (aBuilder->IsForPluginGeometry() ||
-       (f->GetPaintedRect(this) + ToReferenceFrame()).Contains(GetBounds(aBuilder)))) {
-    // We can treat this as opaque
-    result = GetBounds(aBuilder);
+  if (f->IsOpaque()) {
+    nsRect bounds = GetBounds(aBuilder, aSnap);
+    if (aBuilder->IsForPluginGeometry() ||
+        (f->GetPaintedRect(this) + ToReferenceFrame()).Contains(bounds)) {
+      // We can treat this as opaque
+      result = bounds;
+    }
   }
   return result;
 }
 
 void
 nsDisplayPlugin::GetWidgetConfiguration(nsDisplayListBuilder* aBuilder,
                                         nsTArray<nsIWidget::Configuration>* aConfigurations)
 {
--- a/layout/generic/nsObjectFrame.h
+++ b/layout/generic/nsObjectFrame.h
@@ -294,19 +294,20 @@ public:
     MOZ_COUNT_CTOR(nsDisplayPlugin);
   }
 #ifdef NS_BUILD_REFCNT_LOGGING
   virtual ~nsDisplayPlugin() {
     MOZ_COUNT_DTOR(nsDisplayPlugin);
   }
 #endif
 
-  virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder);
+  virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap);
   virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
-                                   bool* aForceTransparentSurface = nsnull);
+                                   bool* aSnap,
+                                   bool* aForceTransparentSurface);
   virtual void Paint(nsDisplayListBuilder* aBuilder,
                      nsRenderingContext* aCtx);
   virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
                                    nsRegion* aVisibleRegion,
                                    const nsRect& aAllowVisibleRegionExpansion);
 
   NS_DISPLAY_DECL_NAME("Plugin", TYPE_PLUGIN)
 
--- a/layout/generic/nsTextFrameThebes.cpp
+++ b/layout/generic/nsTextFrameThebes.cpp
@@ -4384,32 +4384,34 @@ public:
     MOZ_COUNT_CTOR(nsDisplayText);
   }
 #ifdef NS_BUILD_REFCNT_LOGGING
   virtual ~nsDisplayText() {
     MOZ_COUNT_DTOR(nsDisplayText);
   }
 #endif
 
-  virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder) {
+  virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) {
+    *aSnap = false;
     return mFrame->GetVisualOverflowRectRelativeToSelf() + ToReferenceFrame();
   }
   virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
                        HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames) {
     if (nsRect(ToReferenceFrame(), mFrame->GetSize()).Intersects(aRect)) {
       aOutFrames->AppendElement(mFrame);
     }
   }
   virtual void Paint(nsDisplayListBuilder* aBuilder,
                      nsRenderingContext* aCtx);
   NS_DISPLAY_DECL_NAME("Text", TYPE_TEXT)
 
   virtual nsRect GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder)
   {
-    return GetBounds(aBuilder);
+    bool snap;
+    return GetBounds(aBuilder, &snap);
   }
 
   virtual void DisableComponentAlpha() { mDisableSubpixelAA = true; }
 
   bool mDisableSubpixelAA;
 };
 
 void
--- a/layout/generic/nsVideoFrame.cpp
+++ b/layout/generic/nsVideoFrame.cpp
@@ -340,18 +340,19 @@ public:
   // It would be great if we could override GetOpaqueRegion to return nonempty here,
   // but it's probably not safe to do so in general. Video frames are
   // updated asynchronously from decoder threads, and it's possible that
   // we might have an opaque video frame when GetOpaqueRegion is called, but
   // when we come to paint, the video frame is transparent or has gone
   // away completely (e.g. because of a decoder error). The problem would
   // be especially acute if we have off-main-thread rendering.
 
-  virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder)
+  virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap)
   {
+    *aSnap = false;
     nsIFrame* f = GetUnderlyingFrame();
     return f->GetContentRect() - f->GetPosition() + ToReferenceFrame();
   }
 
   virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
                                              LayerManager* aManager,
                                              const ContainerParameters& aContainerParameters)
   {
--- a/layout/ipc/RenderFrameParent.h
+++ b/layout/ipc/RenderFrameParent.h
@@ -193,18 +193,19 @@ public:
                         nsIFrame* aFrame,
                         nsRect aRect,
                         ViewID aId)
     : nsDisplayItem(aBuilder, aFrame)
     , mRect(aRect)
     , mId(aId)
   {}
 
-  NS_OVERRIDE nsRect GetBounds(nsDisplayListBuilder* aBuilder)
+  NS_OVERRIDE nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap)
   {
+    *aSnap = false;
     return mRect;
   }
 
   virtual PRUint32 GetPerFrameKey()
   {
     NS_ABORT();
     return 0;
   }
--- a/layout/mathml/nsMathMLChar.cpp
+++ b/layout/mathml/nsMathMLChar.cpp
@@ -1904,17 +1904,18 @@ public:
     MOZ_COUNT_CTOR(nsDisplayMathMLCharForeground);
   }
 #ifdef NS_BUILD_REFCNT_LOGGING
   virtual ~nsDisplayMathMLCharForeground() {
     MOZ_COUNT_DTOR(nsDisplayMathMLCharForeground);
   }
 #endif
 
-  virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder) {
+  virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) {
+    *aSnap = false;
     nsRect rect;
     mChar->GetRect(rect);
     nsPoint offset = ToReferenceFrame() + rect.TopLeft();
     nsBoundingMetrics bm;
     mChar->GetBoundingMetrics(bm);
     return nsRect(offset.x + bm.leftBearing, offset.y,
                   bm.rightBearing - bm.leftBearing, bm.ascent + bm.descent);
   }
@@ -1925,17 +1926,18 @@ public:
     mChar->PaintForeground(mFrame->PresContext(), *aCtx,
                            ToReferenceFrame(), mIsSelected);
   }
 
   NS_DISPLAY_DECL_NAME("MathMLCharForeground", TYPE_MATHML_CHAR_FOREGROUND)
 
   virtual nsRect GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder)
   {
-    return GetBounds(aBuilder);
+    bool snap;
+    return GetBounds(aBuilder, &snap);
   }
 
 private:
   nsMathMLChar* mChar;
   bool          mIsSelected;
 };
 
 #ifdef NS_DEBUG
--- a/layout/reftests/text-overflow/reftest.list
+++ b/layout/reftests/text-overflow/reftest.list
@@ -2,17 +2,17 @@
 HTTP(..) == marker-basic.html marker-basic-ref.html
 HTTP(..) == marker-string.html marker-string-ref.html
 skip-if(Android) HTTP(..) == bidi-simple.html bidi-simple-ref.html # Fails on Android due to anti-aliasing
 skip-if(!gtk2Widget) HTTP(..) == bidi-simple-scrolled.html bidi-simple-scrolled-ref.html # Fails on Windows and OSX due to anti-aliasing
 HTTP(..) == scroll-rounding.html scroll-rounding-ref.html
 HTTP(..) == anonymous-block.html anonymous-block-ref.html
 HTTP(..) == false-marker-overlap.html false-marker-overlap-ref.html
 HTTP(..) == visibility-hidden.html visibility-hidden-ref.html
-fails-if(Android&&layersOpenGL) HTTP(..) == block-padding.html block-padding-ref.html
+fails-if(Android) HTTP(..) == block-padding.html block-padding-ref.html
 HTTP(..) == quirks-decorations.html quirks-decorations-ref.html
 HTTP(..) == quirks-line-height.html quirks-line-height-ref.html
 HTTP(..) == standards-decorations.html standards-decorations-ref.html
 HTTP(..) == standards-line-height.html standards-line-height-ref.html
 HTTP(..) == selection.html selection-ref.html
 HTTP(..) == marker-shadow.html marker-shadow-ref.html
 == aligned-baseline.html aligned-baseline-ref.html
 skip-if(Android) == clipped-elements.html clipped-elements-ref.html
--- a/layout/tables/nsTableCellFrame.cpp
+++ b/layout/tables/nsTableCellFrame.cpp
@@ -396,35 +396,36 @@ public:
 #endif
 
   virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
                        HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames) {
     aOutFrames->AppendElement(mFrame);
   }
   virtual void Paint(nsDisplayListBuilder* aBuilder,
                      nsRenderingContext* aCtx);
-  virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder);
+  virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap);
 
   NS_DISPLAY_DECL_NAME("TableCellBackground", TYPE_TABLE_CELL_BACKGROUND)
 };
 
 void nsDisplayTableCellBackground::Paint(nsDisplayListBuilder* aBuilder,
                                          nsRenderingContext* aCtx)
 {
   static_cast<nsTableCellFrame*>(mFrame)->
     PaintBackground(*aCtx, mVisibleRect, ToReferenceFrame(),
                     aBuilder->GetBackgroundPaintFlags());
 }
 
 nsRect
-nsDisplayTableCellBackground::GetBounds(nsDisplayListBuilder* aBuilder)
+nsDisplayTableCellBackground::GetBounds(nsDisplayListBuilder* aBuilder,
+                                        bool* aSnap)
 {
   // revert from nsDisplayTableItem's implementation ... cell backgrounds
   // don't overflow the cell
-  return nsDisplayItem::GetBounds(aBuilder);
+  return nsDisplayItem::GetBounds(aBuilder, aSnap);
 }
 
 static void
 PaintTableCellSelection(nsIFrame* aFrame, nsRenderingContext* aCtx,
                         const nsRect& aRect, nsPoint aPt)
 {
   static_cast<nsTableCellFrame*>(aFrame)->DecorateForSelection(*aCtx, aPt);
 }
--- a/layout/tables/nsTableFrame.cpp
+++ b/layout/tables/nsTableFrame.cpp
@@ -1057,17 +1057,18 @@ nsTableFrame::GetChildList(ChildListID a
 void
 nsTableFrame::GetChildLists(nsTArray<ChildList>* aLists) const
 {
   nsContainerFrame::GetChildLists(aLists);
   mColGroups.AppendIfNonempty(aLists, kColGroupList);
 }
 
 nsRect
-nsDisplayTableItem::GetBounds(nsDisplayListBuilder* aBuilder) {
+nsDisplayTableItem::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) {
+  *aSnap = false;
   return mFrame->GetVisualOverflowRectRelativeToSelf() + ToReferenceFrame();
 }
 
 bool
 nsDisplayTableItem::IsVaryingRelativeToMovingFrame(nsDisplayListBuilder* aBuilder,
                                                    nsIFrame* aFrame)
 {
   if (!mPartHasFixedBackground)
--- a/layout/tables/nsTableFrame.h
+++ b/layout/tables/nsTableFrame.h
@@ -73,17 +73,17 @@ public:
       mPartHasFixedBackground(false) {}
 
   virtual bool IsVaryingRelativeToMovingFrame(nsDisplayListBuilder* aBuilder,
                                                 nsIFrame* aFrame);
   // With collapsed borders, parts of the collapsed border can extend outside
   // the table part frames, so allow this display element to blow out to our
   // overflow rect. This is also useful for row frames that have spanning
   // cells extending outside them.
-  virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder);
+  virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap);
 
   void UpdateForFrameBackground(nsIFrame* aFrame);
 
 private:
   bool mPartHasFixedBackground;
 };
 
 class nsAutoPushCurrentTableItem
--- a/layout/xul/base/src/nsTextBoxFrame.cpp
+++ b/layout/xul/base/src/nsTextBoxFrame.cpp
@@ -320,17 +320,17 @@ public:
 #ifdef NS_BUILD_REFCNT_LOGGING
   virtual ~nsDisplayXULTextBox() {
     MOZ_COUNT_DTOR(nsDisplayXULTextBox);
   }
 #endif
 
   virtual void Paint(nsDisplayListBuilder* aBuilder,
                      nsRenderingContext* aCtx);
-  virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder);
+  virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap);
   NS_DISPLAY_DECL_NAME("XULTextBox", TYPE_XUL_TEXT_BOX)
 
   virtual nsRect GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder);
 
   virtual void DisableComponentAlpha() { mDisableSubpixelAA = true; }
 
   void PaintTextToContext(nsRenderingContext* aCtx,
                           nsPoint aOffset,
@@ -373,17 +373,18 @@ nsDisplayXULTextBox::PaintTextToContext(
                                         nsPoint aOffset,
                                         const nscolor* aColor)
 {
   static_cast<nsTextBoxFrame*>(mFrame)->
     PaintTitle(*aCtx, mVisibleRect, ToReferenceFrame() + aOffset, aColor);
 }
 
 nsRect
-nsDisplayXULTextBox::GetBounds(nsDisplayListBuilder* aBuilder) {
+nsDisplayXULTextBox::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) {
+  *aSnap = false;
   return mFrame->GetVisualOverflowRectRelativeToSelf() + ToReferenceFrame();
 }
 
 nsRect
 nsDisplayXULTextBox::GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder)
 {
   return static_cast<nsTextBoxFrame*>(mFrame)->GetComponentAlphaBounds() +
       ToReferenceFrame();
--- a/mobile/android/app/mobile.js
+++ b/mobile/android/app/mobile.js
@@ -701,8 +701,11 @@ pref("media.realtime_decoder.enabled", t
 
 pref("dom.report_all_js_exceptions", true);
 pref("javascript.options.showInConsole", true);
 
 pref("full-screen-api.enabled", true);
 
 pref("direct-texture.force.enabled", false);
 pref("direct-texture.force.disabled", false);
+
+pref("remote-debugger.enabled", false);
+pref("remote-debugger.port", 6000);
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -47,16 +47,21 @@ Cu.import("resource://gre/modules/Servic
 Cu.import("resource://gre/modules/AddonManager.jsm");
 Cu.import("resource://gre/modules/FileUtils.jsm");
 
 XPCOMUtils.defineLazyGetter(this, "PluralForm", function() {
   Cu.import("resource://gre/modules/PluralForm.jsm");
   return PluralForm;
 });
 
+XPCOMUtils.defineLazyGetter(this, "DebuggerServer", function() {
+  Cu.import("resource://gre/modules/devtools/dbg-server.jsm");
+  return DebuggerServer;
+});
+
 // Lazily-loaded browser scripts:
 [
   ["SelectHelper", "chrome://browser/content/SelectHelper.js"],
 ].forEach(function (aScript) {
   let [name, script] = aScript;
   XPCOMUtils.defineLazyGetter(window, name, function() {
     let sandbox = {};
     Services.scriptloader.loadSubScript(script, sandbox);
@@ -232,16 +237,17 @@ var BrowserApp = {
     XPInstallObserver.init();
     ConsoleAPI.init();
     ClipboardHelper.init();
     PermissionsHelper.init();
     CharacterEncoding.init();
     SearchEngines.init();
     ActivityObserver.init();
     WebappsUI.init();
+    RemoteDebugger.init();
 
     // Init LoginManager
     Cc["@mozilla.org/login-manager;1"].getService(Ci.nsILoginManager);
     // Init FormHistory
     Cc["@mozilla.org/satchel/form-history;1"].getService(Ci.nsIFormHistory2);
 
     let url = "about:home";
     let forceRestore = false;
@@ -412,16 +418,17 @@ var BrowserApp = {
     OfflineApps.uninit();
     IndexedDB.uninit();
     ViewportHandler.uninit();
     XPInstallObserver.uninit();
     ConsoleAPI.uninit();
     CharacterEncoding.uninit();
     SearchEngines.uninit();
     WebappsUI.uninit();
+    RemoteDebugger.uninit();
   },
 
   // This function returns false during periods where the browser displayed document is
   // different from the browser content document, so user actions and some kinds of viewport
   // updates should be ignored. This period starts when we start loading a new page or
   // switch tabs, and ends when the new browser content document has been drawn and handed
   // off to the compositor.
   isBrowserContentDocumentDisplayed: function() {
@@ -4613,8 +4620,74 @@ var WebappsUI = {
     if (tab) {
       BrowserApp.selectTab(tab);
     } else {
       tab = BrowserApp.addTab(aURI);
       ss.setTabValue(tab, "appOrigin", aOrigin);
     }
   }
 }
+
+var RemoteDebugger = {
+  init: function rd_init() {
+    Services.prefs.addObserver("remote-debugger.", this, false);
+
+    if (this._isEnabled())
+      this._start();
+  },
+
+  observe: function rd_observe(aSubject, aTopic, aData) {
+    if (aTopic != "nsPref:changed")
+      return;
+
+    switch (aData) {
+      case "remote-debugger.enabled":
+        if (this._isEnabled())
+          this._start();
+        else
+          this._stop();
+        break;
+
+      case "remote-debugger.port":
+        if (this._isEnabled())
+          this._restart();
+        break;
+    }
+  },
+
+  uninit: function rd_uninit() {
+    Services.prefs.removeObserver("remote-debugger.", this);
+    this._stop();
+  },
+
+  _getPort: function _rd_getPort() {
+    return Services.prefs.getIntPref("remote-debugger.port");
+  },
+
+  _isEnabled: function rd_isEnabled() {
+    return Services.prefs.getBoolPref("remote-debugger.enabled");
+  },
+
+  _restart: function rd_restart() {
+    this._stop();
+    this._start();
+  },
+
+  _start: function rd_start() {
+    try {
+      if (!DebuggerServer.initialized) {
+        DebuggerServer.init();
+        DebuggerServer.addActors("chrome://browser/content/dbg-browser-actors.js");
+      }
+
+      let port = this._getPort();
+      DebuggerServer.openListener(port, false);
+      dump("Remote debugger listening on port " + port);
+    } catch(e) {
+      dump("Remote debugger didn't start: " + e);
+    }
+  },
+
+  _stop: function rd_start() {
+    DebuggerServer.closeListener();
+    dump("Remote debugger stopped");
+  }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/chrome/content/dbg-browser-actors.js
@@ -0,0 +1,414 @@
+/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+/**
+ * Fennec-specific actors.
+ */
+
+var windowMediator = Cc["@mozilla.org/appshell/window-mediator;1"]
+  .getService(Ci.nsIWindowMediator);
+
+function createRootActor(aConnection) {
+  return new BrowserRootActor(aConnection);
+}
+
+/**
+ * Creates the root actor that client-server communications always start with.
+ * The root actor is responsible for the initial 'hello' packet and for
+ * responding to a 'listTabs' request that produces the list of currently open
+ * tabs.
+ *
+ * @param aConnection DebuggerServerConnection
+ *        The conection to the client.
+ */
+function BrowserRootActor(aConnection) {
+  this.conn = aConnection;
+  this._tabActors = new WeakMap();
+  this._tabActorPool = null;
+  this._actorFactories = null;
+
+  this.onTabClosed = this.onTabClosed.bind(this);
+  windowMediator.addListener(this);
+}
+
+BrowserRootActor.prototype = {
+  /**
+   * Return a 'hello' packet as specified by the Remote Debugging Protocol.
+   */
+  sayHello: function BRA_sayHello() {
+    return { from: "root",
+             applicationType: "browser",
+             traits: [] };
+  },
+
+  /**
+   * Disconnects the actor from the browser window.
+   */
+  disconnect: function BRA_disconnect() {
+    windowMediator.removeListener(this);
+
+    // We may have registered event listeners on browser windows to
+    // watch for tab closes, remove those.
+    let win = windowMediator.getMostRecentWindow("navigator:browser");
+    this.unwatchWindow(win);
+
+    // Signal our imminent shutdown.
+    let evt = win.document.createEvent("Event");
+    evt.initEvent("Debugger:Shutdown", true, false);
+    win.document.documentElement.dispatchEvent(evt);
+  },
+
+  /**
+   * Handles the listTabs request.  Builds a list of actors
+   * for the tabs running in the process.  The actors will survive
+   * until at least the next listTabs request.
+   */
+  onListTabs: function BRA_onListTabs() {
+    // Get actors for all the currently-running tabs (reusing
+    // existing actors where applicable), and store them in
+    // an ActorPool.
+
+    let actorPool = new ActorPool(this.conn);
+    let actorList = [];
+
+    let win = windowMediator.getMostRecentWindow("navigator:browser");
+    this.browser = win.BrowserApp.selectedBrowser;
+
+    // Watch the window for tab closes so we can invalidate
+    // actors as needed.
+    this.watchWindow(win);
+
+    let tabs = win.BrowserApp.tabs;
+    let selected;
+
+    for each (let tab in tabs) {
+      let browser = tab.browser;
+
+      if (browser == this.browser) {
+        selected = actorList.length;
+      }
+
+      let actor = this._tabActors.get(browser);
+      if (!actor) {
+        actor = new BrowserTabActor(this.conn, browser);
+        actor.parentID = this.actorID;
+        this._tabActors.set(browser, actor);
+      }
+
+      actorPool.addActor(actor);
+      actorList.push(actor);
+    }
+
+    // Now drop the old actorID -> actor map.  Actors that still
+    // mattered were added to the new map, others will go
+    // away.
+    if (this._tabActorPool) {
+      this.conn.removeActorPool(this._tabActorPool);
+    }
+
+    this._tabActorPool = actorPool;
+    this.conn.addActorPool(this._tabActorPool);
+
+    return { "from": "root",
+             "selected": selected,
+             "tabs": [actor.grip()
+                      for each (actor in actorList)] };
+  },
+
+  /**
+   * Watch a window that was visited during onListTabs for
+   * tab closures.
+   */
+  watchWindow: function BRA_watchWindow(aWindow) {
+    let tabContainer = aWindow.document.getElementById("browsers");
+    tabContainer.addEventListener("TabClose",
+                                  this.onTabClosed,
+                                  false);
+  },
+
+  /**
+   * Stop watching a window for tab closes.
+   */
+  unwatchWindow: function BRA_unwatchWindow(aWindow) {
+    let tabContainer = aWindow.document.getElementById("browsers");
+    tabContainer.removeEventListener("TabClose", this.onTabClosed);
+    this.exitTabActor(aWindow);
+  },
+
+  /**
+   * When a tab is closed, exit its tab actor.  The actor
+   * will be dropped at the next listTabs request.
+   */
+  onTabClosed: function BRA_onTabClosed(aEvent) {
+    this.exitTabActor(aEvent.target.browser);
+  },
+
+  /**
+   * Exit the tab actor of the specified tab.
+   */
+  exitTabActor: function BRA_exitTabActor(aWindow) {
+    let actor = this._tabActors.get(aWindow);
+    if (actor) {
+      actor.exit();
+    }
+  },
+
+  // nsIWindowMediatorListener
+  onWindowTitleChange: function BRA_onWindowTitleChange(aWindow, aTitle) { },
+  onOpenWindow: function BRA_onOpenWindow(aWindow) { },
+  onCloseWindow: function BRA_onCloseWindow(aWindow) {
+    if (aWindow.BrowserApp) {
+      this.unwatchWindow(aWindow);
+    }
+  }
+}
+
+/**
+ * The request types this actor can handle.
+ */
+BrowserRootActor.prototype.requestTypes = {
+  "listTabs": BrowserRootActor.prototype.onListTabs
+};
+
+/**
+ * Creates a tab actor for handling requests to a browser tab, like attaching
+ * and detaching.
+ *
+ * @param aConnection DebuggerServerConnection
+ *        The conection to the client.
+ * @param aBrowser browser
+ *        The browser instance that contains this tab.
+ */
+function BrowserTabActor(aConnection, aBrowser)
+{
+  this.conn = aConnection;
+  this._browser = aBrowser;
+
+  this._onWindowCreated = this.onWindowCreated.bind(this);
+}
+
+// XXX (bug 710213): BrowserTabActor attach/detach/exit/disconnect is a
+// *complete* mess, needs to be rethought asap.
+
+BrowserTabActor.prototype = {
+  get browser() { return this._browser; },
+
+  get exited() { return !this._browser; },
+  get attached() { return !!this._attached },
+
+  _tabPool: null,
+  get tabActorPool() { return this._tabPool; },
+
+  _contextPool: null,
+  get contextActorPool() { return this._contextPool; },
+
+  actorPrefix: "tab",
+
+  grip: function BTA_grip() {
+    dbg_assert(!this.exited,
+               "grip() shouldn't be called on exited browser actor.");
+    dbg_assert(this.actorID,
+               "tab should have an actorID.");
+    return { actor: this.actorID,
+             title: this._browser.contentTitle,
+             url: this._browser.currentURI.spec }
+  },
+
+  /**
+   * Called when the actor is removed from the connection.
+   */
+  disconnect: function BTA_disconnect() {
+    this._detach();
+  },
+
+  /**
+   * Called by the root actor when the underlying tab is closed.
+   */
+  exit: function BTA_exit() {
+    if (this.exited) {
+      return;
+    }
+
+    if (this.attached) {
+      this._detach();
+      this.conn.send({ from: this.actorID,
+                       type: "tabDetached" });
+    }
+
+    this._browser = null;
+  },
+
+  /**
+   * Does the actual work of attching to a tab.
+   */
+  _attach: function BTA_attach() {
+    if (this._attached) {
+      return;
+    }
+
+    // Create a pool for tab-lifetime actors.
+    dbg_assert(!this._tabPool, "Shouldn't have a tab pool if we weren't attached.");
+    this._tabPool = new ActorPool(this.conn);
+    this.conn.addActorPool(this._tabPool);
+
+    // ... and a pool for context-lifetime actors.
+    this._pushContext();
+
+    // Watch for globals being created in this tab.
+    this._browser.addEventListener("DOMWindowCreated", this._onWindowCreated, true);
+
+    this._attached = true;
+  },
+
+  /**
+   * Creates a thread actor and a pool for context-lifetime actors. It then sets
+   * up the content window for debugging.
+   */
+  _pushContext: function BTA_pushContext() {
+    dbg_assert(!this._contextPool, "Can't push multiple contexts");
+
+    this._contextPool = new ActorPool(this.conn);
+    this.conn.addActorPool(this._contextPool);
+
+    this.threadActor = new ThreadActor(this);
+    this._addDebuggees(this._browser.contentWindow.wrappedJSObject);
+    this._contextPool.addActor(this.threadActor);
+  },
+
+  /**
+   * Add the provided window and all windows in its frame tree as debuggees.
+   */
+  _addDebuggees: function BTA__addDebuggees(aWindow) {
+    this.threadActor.addDebuggee(aWindow);
+    let frames = aWindow.frames;
+    for (let i = 0; i < frames.length; i++) {
+      this._addDebuggees(frames[i]);
+    }
+  },
+
+  /**
+   * Exits the current thread actor and removes the context-lifetime actor pool.
+   * The content window is no longer being debugged after this call.
+   */
+  _popContext: function BTA_popContext() {
+    dbg_assert(!!this._contextPool, "No context to pop.");
+
+    this.conn.removeActorPool(this._contextPool);
+    this._contextPool = null;
+    this.threadActor.exit();
+    this.threadActor = null;
+  },
+
+  /**
+   * Does the actual work of detaching from a tab.
+   */
+  _detach: function BTA_detach() {
+    if (!this.attached) {
+      return;
+    }
+
+    this._browser.removeEventListener("DOMWindowCreated", this._onWindowCreated, true);
+
+    this._popContext();
+
+    // Shut down actors that belong to this tab's pool.
+    this.conn.removeActorPool(this._tabPool);
+    this._tabPool = null;
+
+    this._attached = false;
+  },
+
+  // Protocol Request Handlers
+
+  onAttach: function BTA_onAttach(aRequest) {
+    if (this.exited) {
+      return { type: "exited" };
+    }
+
+    this._attach();
+
+    return { type: "tabAttached", threadActor: this.threadActor.actorID };
+  },
+
+  onDetach: function BTA_onDetach(aRequest) {
+    if (!this.attached) {
+      return { error: "wrongState" };
+    }
+
+    this._detach();
+
+    return { type: "detached" };
+  },
+
+  /**
+   * Prepare to enter a nested event loop by disabling debuggee events.
+   */
+  preNest: function BTA_preNest() {
+    if (!this._browser) {
+      // The tab is already closed.
+      return;
+    }
+    let windowUtils = this._browser.contentWindow
+                          .QueryInterface(Ci.nsIInterfaceRequestor)
+                          .getInterface(Ci.nsIDOMWindowUtils);
+    windowUtils.suppressEventHandling(true);
+    windowUtils.suspendTimeouts();
+  },
+
+  /**
+   * Prepare to exit a nested event loop by enabling debuggee events.
+   */
+  postNest: function BTA_postNest(aNestData) {
+    if (!this._browser) {
+      // The tab is already closed.
+      return;
+    }
+    let windowUtils = this._browser.contentWindow
+                          .QueryInterface(Ci.nsIInterfaceRequestor)
+                          .getInterface(Ci.nsIDOMWindowUtils);
+    windowUtils.resumeTimeouts();
+    windowUtils.suppressEventHandling(false);
+  },
+
+  /**
+   * Handle location changes, by sending a tabNavigated notification to the
+   * client.
+   */
+  onWindowCreated: function BTA_onWindowCreated(evt) {
+    if (evt.target === this._browser.contentDocument) {
+      if (this._attached) {
+        this.conn.send({ from: this.actorID, type: "tabNavigated",
+                         url: this._browser.contentDocument.URL });
+      }
+    }
+  }
+};
+
+/**
+ * The request types this actor can handle.
+ */
+BrowserTabActor.prototype.requestTypes = {
+  "attach": BrowserTabActor.prototype.onAttach,
+  "detach": BrowserTabActor.prototype.onDetach
+};
+
+/**
+ * Registers handlers for new request types defined dynamically. This is used
+ * for example by add-ons to augment the functionality of the tab actor.
+ *
+ * @param aName string
+ *        The name of the new request type.
+ * @param aFunction function
+ *        The handler for this request type.
+ */
+DebuggerServer.addTabRequest = function DS_addTabRequest(aName, aFunction) {
+  BrowserTabActor.prototype.requestTypes[aName] = function(aRequest) {
+    if (!this.attached) {
+      return { error: "wrongState" };
+    }
+    return aFunction(this, aRequest);
+  }
+};
--- a/mobile/android/chrome/jar.mn
+++ b/mobile/android/chrome/jar.mn
@@ -25,12 +25,13 @@ chrome.jar:
   content/browser.css                  (content/browser.css)
   content/cursor.css                   (content/cursor.css)
 % content branding %content/branding/
   content/sanitize.js                  (content/sanitize.js)
   content/exceptions.js                (content/exceptions.js)
 * content/downloads.js                 (content/downloads.js)
   content/netError.xhtml               (content/netError.xhtml)
   content/SelectHelper.js              (content/SelectHelper.js)
+  content/dbg-browser-actors.js        (content/dbg-browser-actors.js)
 
 % override chrome://global/content/config.xul chrome://browser/content/config.xhtml
 % override chrome://global/content/netError.xhtml chrome://browser/content/netError.xhtml
 % override chrome://mozapps/content/extensions/extensions.xul chrome://browser/content/aboutAddons.xhtml
--- a/mobile/android/installer/package-manifest.in
+++ b/mobile/android/installer/package-manifest.in
@@ -194,16 +194,18 @@
 @BINPATH@/components/htmlparser.xpt
 @BINPATH@/components/imglib2.xpt
 @BINPATH@/components/imgicon.xpt
 @BINPATH@/components/inspector.xpt
 @BINPATH@/components/intl.xpt
 @BINPATH@/components/jar.xpt
 @BINPATH@/components/jetpack.xpt
 @BINPATH@/components/jsdservice.xpt
+@BINPATH@/components/jsdebugger.xpt
+@BINPATH@/components/jsinspector.xpt
 @BINPATH@/components/layout_base.xpt
 @BINPATH@/components/layout_forms.xpt
 #ifdef NS_PRINTING
 @BINPATH@/components/layout_printing.xpt
 #endif
 @BINPATH@/components/layout_xul_tree.xpt
 @BINPATH@/components/layout_xul.xpt
 @BINPATH@/components/locale.xpt
--- a/parser/htmlparser/src/nsParser.cpp
+++ b/parser/htmlparser/src/nsParser.cpp
@@ -2101,17 +2101,17 @@ nsParser::OnDataAvailable(nsIRequest *re
                    eOnDataAvail == mParserContext->mStreamListenerState),
             "Error: OnStartRequest() must be called before OnDataAvailable()");
   NS_PRECONDITION(NS_InputStreamIsBuffered(pIStream),
                   "Must have a buffered input stream");
 
   nsresult rv = NS_OK;
 
   if (mIsAboutBlank) {
-    MOZ_NOT_REACHED("Must not get OnDataAvailable for about:blank");
+    MOZ_ASSERT(false, "Must not get OnDataAvailable for about:blank");
     // ... but if an extension tries to feed us data for about:blank in a
     // release build, silently ignore the data.
     PRUint32 totalRead;
     rv = pIStream->ReadSegments(NoOpParserWriteFunc,
                                 nsnull,
                                 aLength,
                                 &totalRead);
     return rv;
--- a/toolkit/mozapps/update/nsUpdateTimerManager.js
+++ b/toolkit/mozapps/update/nsUpdateTimerManager.js
@@ -216,17 +216,19 @@ TimerManager.prototype = {
 
       let interval = getPref("getIntPref", prefInterval, defaultInterval);
       let prefLastUpdate = PREF_APP_UPDATE_LASTUPDATETIME_FMT.replace(/%ID%/,
                                                                   timerID);
       if (Services.prefs.prefHasUserValue(prefLastUpdate)) {
         lastUpdateTime = Services.prefs.getIntPref(prefLastUpdate);
       }
       else {
-        lastUpdateTime = now;
+        // Initialize the last update time to 0 so that we check for
+        // an update the first time the interval expires.
+        lastUpdateTime = 0;
         Services.prefs.setIntPref(prefLastUpdate, lastUpdateTime);
       }
 
       tryFire(function() {
         try {
           Components.classes[cid][method](Ci.nsITimerCallback).notify(timer);
           LOG("TimerManager:notify - notified " + cid);
         }
--- a/widget/android/nsAppShell.cpp
+++ b/widget/android/nsAppShell.cpp
@@ -90,17 +90,18 @@ nsAppShell *nsAppShell::gAppShell = nsnu
 
 NS_IMPL_ISUPPORTS_INHERITED1(nsAppShell, nsBaseAppShell, nsIObserver)
 
 nsAppShell::nsAppShell()
     : mQueueLock("nsAppShell.mQueueLock"),
       mCondLock("nsAppShell.mCondLock"),
       mQueueCond(mCondLock, "nsAppShell.mQueueCond"),
       mQueuedDrawEvent(nsnull),
-      mQueuedViewportEvent(nsnull)
+      mQueuedViewportEvent(nsnull),
+      mAllowCoalescingNextDraw(false)
 {
     gAppShell = this;
 }
 
 nsAppShell::~nsAppShell()
 {
     gAppShell = nsnull;
 }
@@ -511,16 +512,21 @@ nsAppShell::PeekNextEvent()
 
     return ae;
 }
 
 void
 nsAppShell::PostEvent(AndroidGeckoEvent *ae)
 {
     {
+        // set this to true when inserting events that we can coalesce
+        // viewport events across. this is effectively maintaining a whitelist
+        // of events that are unaffected by viewport changes.
+        bool allowCoalescingNextViewport = false;
+
         MutexAutoLock lock(mQueueLock);
         EVLOG("nsAppShell::PostEvent %p %d", ae, ae->Type());
         switch (ae->Type()) {
         case AndroidGeckoEvent::SURFACE_DESTROYED:
             // Give priority to this event, and discard any pending
             // SURFACE_CREATED events.
             mEventQueue.InsertElementAt(0, ae);
             AndroidGeckoEvent *event;
@@ -571,28 +577,44 @@ nsAppShell::PostEvent(AndroidGeckoEvent 
                 // be events between the two draws that affect scroll position or something.
                 ae->Init(AndroidGeckoEvent::DRAW, combinedRect);
 
                 EVLOG("nsAppShell: Coalescing previous DRAW event at %p into new DRAW event %p", mQueuedDrawEvent, ae);
                 mEventQueue.RemoveElement(mQueuedDrawEvent);
                 delete mQueuedDrawEvent;
             }
 
-            mQueuedDrawEvent = ae;
+            if (mAllowCoalescingNextDraw) {
+                // if we're not allowing coalescing of this draw event, then
+                // don't set mQueuedDrawEvent to point to this; that way the
+                // next draw event that comes in won't kill this one.
+                mAllowCoalescingNextDraw = true;
+                mQueuedDrawEvent = nsnull;
+            } else {
+                mQueuedDrawEvent = ae;
+            }
+
+            allowCoalescingNextViewport = true;
+
             mEventQueue.AppendElement(ae);
             break;
 
         case AndroidGeckoEvent::VIEWPORT:
             if (mQueuedViewportEvent) {
                 // drop the previous viewport event now that we have a new one
                 EVLOG("nsAppShell: Dropping old viewport event at %p in favour of new VIEWPORT event %p", mQueuedViewportEvent, ae);
                 mEventQueue.RemoveElement(mQueuedViewportEvent);
                 delete mQueuedViewportEvent;
             }
             mQueuedViewportEvent = ae;
+            // temporarily turn off draw-coalescing, so that we process a draw
+            // event as soon as possible after a viewport change
+            mAllowCoalescingNextDraw = false;
+            allowCoalescingNextViewport = true;
+
             mEventQueue.AppendElement(ae);
             break;
 
         case AndroidGeckoEvent::MOTION_EVENT:
             if (ae->Action() == AndroidMotionEvent::ACTION_MOVE) {
                 int len = mEventQueue.Length();
                 if (len > 0) {
                     AndroidGeckoEvent* event = mEventQueue[len - 1];
@@ -602,20 +624,30 @@ nsAppShell::PostEvent(AndroidGeckoEvent 
                         mEventQueue.RemoveElementAt(len - 1);
                         delete event;
                     }
                 }
             }
             mEventQueue.AppendElement(ae);
             break;
 
+        case AndroidGeckoEvent::NATIVE_POKE:
+            allowCoalescingNextViewport = true;
+            // fall through
+
         default:
             mEventQueue.AppendElement(ae);
             break;
         }
+
+        // if the event wasn't on our whitelist then reset mQueuedViewportEvent
+        // so that we don't coalesce future viewport events into the last viewport
+        // event we added
+        if (!allowCoalescingNextViewport)
+            mQueuedViewportEvent = nsnull;
     }
     NotifyNativeEvent();
 }
 
 void
 nsAppShell::OnResume()
 {
 }
--- a/widget/android/nsAppShell.h
+++ b/widget/android/nsAppShell.h
@@ -97,16 +97,17 @@ protected:
     virtual void ScheduleNativeEventCallback();
     virtual ~nsAppShell();
 
     Mutex mQueueLock;
     Mutex mCondLock;
     CondVar mQueueCond;
     mozilla::AndroidGeckoEvent *mQueuedDrawEvent;
     mozilla::AndroidGeckoEvent *mQueuedViewportEvent;
+    bool mAllowCoalescingNextDraw;
     nsTArray<mozilla::AndroidGeckoEvent *> mEventQueue;
     nsInterfaceHashtable<nsStringHashKey, nsIObserver> mObserversHash;
 
     mozilla::AndroidGeckoEvent *PopNextEvent();
     mozilla::AndroidGeckoEvent *PeekNextEvent();
 
     nsCOMPtr<nsIAndroidBrowserApp> mBrowserApp;
 };