Backing out bug 579276. a=me
authorRobert O'Callahan <robert@ocallahan.org>
Thu, 02 Sep 2010 23:14:25 +1200
changeset 51885 0d05f0b5bfd4a17e804b9b8a04022a5524433f86
parent 51884 ba5675370e8e57aca5b5ba6a33c7ae90b5678912
child 51886 dc2939f2640dc3d46cf1ee99fad45e171e100b4f
push idunknown
push userunknown
push dateunknown
reviewersme
bugs579276
milestone2.0b6pre
Backing out bug 579276. a=me
content/canvas/src/WebGLContext.cpp
content/canvas/src/nsCanvasRenderingContext2D.cpp
gfx/layers/Layers.cpp
gfx/layers/Layers.h
gfx/layers/basic/BasicLayers.cpp
gfx/layers/d3d9/ThebesLayerD3D9.cpp
gfx/layers/ipc/PLayers.ipdl
gfx/layers/ipc/ShadowLayers.cpp
gfx/layers/ipc/ShadowLayersParent.cpp
gfx/thebes/gfxASurface.h
gfx/thebes/gfxD2DSurface.h
gfx/thebes/gfxQuartzSurface.h
gfx/thebes/gfxWindowsSurface.h
gfx/thebes/gfxXlibSurface.h
layout/base/FrameLayerBuilder.cpp
layout/base/FrameLayerBuilder.h
layout/generic/nsGfxScrollFrame.cpp
layout/reftests/bidi/logicalmarquee.html
layout/reftests/bidi/marquee-ref.html
layout/reftests/bidi/visualmarquee.html
layout/reftests/marquee/413027-4-ref.html
layout/reftests/marquee/413027-4.html
layout/reftests/scrolling/fixed-text-1.html
layout/reftests/scrolling/reftest.list
layout/reftests/scrolling/text-1.html
--- a/content/canvas/src/WebGLContext.cpp
+++ b/content/canvas/src/WebGLContext.cpp
@@ -58,17 +58,16 @@
 #ifdef MOZ_SVG
 #include "nsSVGEffects.h"
 #endif
 
 #include "prenv.h"
 
 using namespace mozilla;
 using namespace mozilla::gl;
-using namespace mozilla::layers;
 
 nsresult NS_NewCanvasRenderingContextWebGL(nsICanvasRenderingContextWebGL** aResult);
 
 nsresult
 NS_NewCanvasRenderingContextWebGL(nsICanvasRenderingContextWebGL** aResult)
 {
     nsICanvasRenderingContextWebGL* ctx = new WebGLContext();
     if (!ctx)
@@ -504,31 +503,31 @@ WebGLContext::GetThebesSurface(gfxASurfa
 
 static PRUint8 gWebGLLayerUserData;
 
 already_AddRefed<layers::CanvasLayer>
 WebGLContext::GetCanvasLayer(CanvasLayer *aOldLayer,
                              LayerManager *aManager)
 {
     if (!mResetLayer && aOldLayer &&
-        aOldLayer->HasUserData(&gWebGLLayerUserData)) {
+        aOldLayer->GetUserData() == &gWebGLLayerUserData) {
         NS_ADDREF(aOldLayer);
         if (mInvalidated) {
             aOldLayer->Updated(nsIntRect(0, 0, mWidth, mHeight));
             mInvalidated = PR_FALSE;
         }
         return aOldLayer;
     }
 
     nsRefPtr<CanvasLayer> canvasLayer = aManager->CreateCanvasLayer();
     if (!canvasLayer) {
         NS_WARNING("CreateCanvasLayer returned null!");
         return nsnull;
     }
-    canvasLayer->SetUserData(&gWebGLLayerUserData, nsnull);
+    canvasLayer->SetUserData(&gWebGLLayerUserData);
 
     CanvasLayer::Data data;
 
     // the gl context may either provide a native PBuffer, in which case we want to initialize
     // data with the gl context directly, or may provide a surface to which it renders (this is the case
     // of OSMesa contexts), in which case we want to initialize data with that surface.
 
     void* native_surface = gl->GetNativeData(gl::GLContext::NativeImageSurface);
@@ -538,18 +537,17 @@ WebGLContext::GetCanvasLayer(CanvasLayer
     } else {
         data.mGLContext = gl.get();
     }
 
     data.mSize = nsIntSize(mWidth, mHeight);
     data.mGLBufferIsPremultiplied = PR_FALSE;
 
     canvasLayer->Initialize(data);
-    PRUint32 flags = gl->CreationFormat().alpha == 0 ? Layer::CONTENT_OPAQUE : 0;
-    canvasLayer->SetContentFlags(flags);
+    canvasLayer->SetIsOpaqueContent(gl->CreationFormat().alpha == 0 ? PR_TRUE : PR_FALSE);
     canvasLayer->Updated(nsIntRect(0, 0, mWidth, mHeight));
 
     mInvalidated = PR_FALSE;
     mResetLayer = PR_FALSE;
 
     return canvasLayer.forget().get();
 }
 
--- a/content/canvas/src/nsCanvasRenderingContext2D.cpp
+++ b/content/canvas/src/nsCanvasRenderingContext2D.cpp
@@ -4149,38 +4149,37 @@ static PRUint8 g2DContextLayerUserData;
 already_AddRefed<CanvasLayer>
 nsCanvasRenderingContext2D::GetCanvasLayer(CanvasLayer *aOldLayer,
                                            LayerManager *aManager)
 {
     if (!mValid)
         return nsnull;
 
     if (!mResetLayer && aOldLayer &&
-        aOldLayer->HasUserData(&g2DContextLayerUserData)) {
+        aOldLayer->GetUserData() == &g2DContextLayerUserData) {
         NS_ADDREF(aOldLayer);
         // XXX Need to just update the changed area here
         aOldLayer->Updated(nsIntRect(0, 0, mWidth, mHeight));
         return aOldLayer;
     }
 
     nsRefPtr<CanvasLayer> canvasLayer = aManager->CreateCanvasLayer();
     if (!canvasLayer) {
         NS_WARNING("CreateCanvasLayer returned null!");
         return nsnull;
     }
-    canvasLayer->SetUserData(&g2DContextLayerUserData, nsnull);
+    canvasLayer->SetUserData(&g2DContextLayerUserData);
 
     CanvasLayer::Data data;
 
     data.mSurface = mSurface.get();
     data.mSize = nsIntSize(mWidth, mHeight);
 
     canvasLayer->Initialize(data);
-    PRUint32 flags = mOpaque ? Layer::CONTENT_OPAQUE : 0;
-    canvasLayer->SetContentFlags(flags);
+    canvasLayer->SetIsOpaqueContent(mOpaque);
     canvasLayer->Updated(nsIntRect(0, 0, mWidth, mHeight));
 
     mResetLayer = PR_FALSE;
     return canvasLayer.forget().get();
 }
 
 void
 nsCanvasRenderingContext2D::MarkContextClean()
--- a/gfx/layers/Layers.cpp
+++ b/gfx/layers/Layers.cpp
@@ -142,17 +142,17 @@ namespace layers {
 //--------------------------------------------------
 // Layer
 
 PRBool
 Layer::CanUseOpaqueSurface()
 {
   // If the visible content in the layer is opaque, there is no need
   // for an alpha channel.
-  if (GetContentFlags() & CONTENT_OPAQUE)
+  if (IsOpaqueContent())
     return PR_TRUE;
   // Also, if this layer is the bottommost layer in a container which
   // doesn't need an alpha channel, we can use an opaque surface for this
   // layer too. Any transparent areas must be covered by something else
   // in the container.
   ContainerLayer* parent = GetParent();
   return parent && parent->GetFirstChild() == this &&
     parent->CanUseOpaqueSurface();
@@ -216,34 +216,24 @@ nsACString&
 Layer::PrintInfo(nsACString& aTo, const char* aPrefix)
 {
   aTo += aPrefix;
   aTo += nsPrintfCString(64, "%s%s (0x%p)", mManager->Name(), Name(), this);
 
   if (mUseClipRect) {
     AppendToString(aTo, mClipRect, " [clip=", "]");
   }
-  if (!mTransform.IsIdentity()) {
+  if (!mTransform.IsIdentity())
     AppendToString(aTo, mTransform, " [transform=", "]");
-  }
-  if (!mVisibleRegion.IsEmpty()) {
+  if (!mVisibleRegion.IsEmpty())
     AppendToString(aTo, mVisibleRegion, " [visible=", "]");
-  }
-  if (1.0 != mOpacity) {
+  if (1.0 != mOpacity)
     aTo.AppendPrintf(" [opacity=%g]", mOpacity);
-  }
-  if (GetContentFlags() & CONTENT_OPAQUE) {
+  if (IsOpaqueContent())
     aTo += " [opaqueContent]";
-  }
-  if (GetContentFlags() & CONTENT_NO_TEXT) {
-    aTo += " [noText]";
-  }
-  if (GetContentFlags() & CONTENT_NO_TEXT_OVER_TRANSPARENT) {
-    aTo += " [noTextOverTransparent]";
-  }
 
   return aTo;
 }
 
 nsACString&
 ThebesLayer::PrintInfo(nsACString& aTo, const char* aPrefix)
 {
   Layer::PrintInfo(aTo, aPrefix);
--- a/gfx/layers/Layers.h
+++ b/gfx/layers/Layers.h
@@ -78,24 +78,16 @@ class ColorLayer;
 class ImageContainer;
 class CanvasLayer;
 class SpecificLayerAttributes;
 
 #define MOZ_LAYER_DECL_NAME(n, e)                           \
   virtual const char* Name() const { return n; }            \
   virtual LayerType GetType() const { return e; }
 
-/**
- * Base class for userdata objects attached to layers and layer managers.
- */
-class THEBES_API LayerUserData {
-public:
-  virtual ~LayerUserData() {}
-};
-
 /*
  * Motivation: For truly smooth animation and video playback, we need to
  * be able to compose frames and render them on a dedicated thread (i.e.
  * off the main thread where DOM manipulation, script execution and layout
  * induce difficult-to-bound latency). This requires Gecko to construct
  * some kind of persistent scene structure (graph or tree) that can be
  * safely transmitted across threads. We have other scenarios (e.g. mobile 
  * browsing) where retaining some rendered data between paints is desired
@@ -113,62 +105,16 @@ public:
  * Gecko used it before layers were introduced). But we also don't want
  * to have bifurcated "layers"/"non-layers" rendering paths in Gecko.
  * Therefore the layers API is carefully designed to permit maximally
  * efficient implementation in an "immediate mode" style. See the
  * BasicLayerManager for such an implementation.
  */
 
 /**
- * Helper class to manage user data for layers and LayerManagers.
- */
-class THEBES_API LayerUserDataSet {
-public:
-  LayerUserDataSet() : mKey(nsnull) {}
-
-  void Set(void* aKey, LayerUserData* aValue)
-  {
-    NS_ASSERTION(!mKey || mKey == aKey,
-                 "Multiple LayerUserData objects not supported");
-    mKey = aKey;
-    mValue = aValue;
-  }
-  /**
-   * This can be used anytime. Ownership passes to the caller!
-   */
-  LayerUserData* Remove(void* aKey)
-  {
-    if (mKey == aKey) {
-      mKey = nsnull;
-      LayerUserData* d = mValue.forget();
-      return d;
-    }
-    return nsnull;
-  }
-  /**
-   * This getter can be used anytime.
-   */
-  PRBool Has(void* aKey)
-  {
-    return mKey == aKey;
-  }
-  /**
-   * This getter can be used anytime. Ownership is retained by this object.
-   */
-  LayerUserData* Get(void* aKey)
-  {
-    return mKey == aKey ? mValue.get() : nsnull;
-  }
-
-private:
-  void* mKey;
-  nsAutoPtr<LayerUserData> mValue;
-};
-
-/**
  * A LayerManager controls a tree of layers. All layers in the tree
  * must use the same LayerManager.
  * 
  * All modifications to a layer tree must happen inside a transaction.
  * Only the state of the layer tree at the end of a transaction is
  * rendered. Transactions cannot be nested
  * 
  * Each transaction has two phases:
@@ -191,17 +137,17 @@ class THEBES_API LayerManager {
 
 public:
   enum LayersBackend {
     LAYERS_BASIC = 0,
     LAYERS_OPENGL,
     LAYERS_D3D9
   };
 
-  LayerManager() : mDestroyed(PR_FALSE)
+  LayerManager() : mUserData(nsnull), mDestroyed(PR_FALSE)
   {
     InitLog();
   }
   virtual ~LayerManager() {}
 
   /**
    * Release layers and resources held by this layer manager, and mark
    * it as destroyed.  Should do any cleanup necessary in preparation
@@ -316,38 +262,20 @@ public:
 
   /**
    * Type of layer manager his is. This is to be used sparsely in order to
    * avoid a lot of Layers backend specific code. It should be used only when
    * Layers backend specific functionality is necessary.
    */
   virtual LayersBackend GetBackendType() = 0;
 
-  /**
-   * This setter can be used anytime. The user data for all keys is
-   * initially null. Ownership pases to the layer manager.
-   */
-  void SetUserData(void* aKey, LayerUserData* aData)
-  { mUserData.Set(aKey, aData); }
-  /**
-   * This can be used anytime. Ownership passes to the caller!
-   */
-  nsAutoPtr<LayerUserData> RemoveUserData(void* aKey)
-  { nsAutoPtr<LayerUserData> d(mUserData.Remove(aKey)); return d; }
-  /**
-   * This getter can be used anytime.
-   */
-  PRBool HasUserData(void* aKey)
-  { return mUserData.Has(aKey); }
-  /**
-   * This getter can be used anytime. Ownership is retained by the layer
-   * manager.
-   */
-  LayerUserData* GetUserData(void* aKey)
-  { return mUserData.Get(aKey); }
+  // This setter and getter can be used anytime. The user data is initially
+  // null.
+  void SetUserData(void* aData) { mUserData = aData; }
+  void* GetUserData() { return mUserData; }
 
   // We always declare the following logging symbols, because it's
   // extremely tricky to conditionally declare them.  However, for
   // ifndef MOZ_LAYERS_HAVE_LOG builds, they only have trivial
   // definitions in Layers.cpp.
   virtual const char* Name() const { return "???"; }
 
   /**
@@ -372,17 +300,17 @@ public:
    */
   void LogSelf(const char* aPrefix="");
 
   static bool IsLogEnabled();
   static PRLogModuleInfo* GetLog() { return sLog; }
 
 protected:
   nsRefPtr<Layer> mRoot;
-  LayerUserDataSet mUserData;
+  void* mUserData;
   PRPackedBool mDestroyed;
 
   // Print interesting information about this into aTo.  Internally
   // used to implement Dump*() and Log*().
   virtual nsACString& PrintInfo(nsACString& aTo, const char* aPrefix);
 
   static void InitLog();
   static PRLogModuleInfo* sLog;
@@ -411,47 +339,27 @@ public:
 
   /**
    * Returns the LayerManager this Layer belongs to. Note that the layer
    * manager might be in a destroyed state, at which point it's only
    * valid to set/get user data from it.
    */
   LayerManager* Manager() { return mManager; }
 
-  enum {
-    /**
-     * If this is set, the caller is promising that by the end of this
-     * transaction the entire visible region (as specified by
-     * SetVisibleRegion) will be filled with opaque content.
-     */
-    CONTENT_OPAQUE = 0x01,
-    /**
-     * ThebesLayers only!
-     * If this is set, the caller is promising that the visible region
-     * contains no text at all. If this is set,
-     * CONTENT_NO_TEXT_OVER_TRANSPARENT will also be set.
-     */
-    CONTENT_NO_TEXT = 0x02,
-    /**
-     * ThebesLayers only!
-     * If this is set, the caller is promising that the visible region
-     * contains no text over transparent pixels (any text, if present,
-     * is over fully opaque pixels).
-     */
-    CONTENT_NO_TEXT_OVER_TRANSPARENT = 0x04
-  };
   /**
    * CONSTRUCTION PHASE ONLY
-   * This lets layout make some promises about what will be drawn into the
-   * visible region of the ThebesLayer. This enables internal quality
-   * and performance optimizations.
+   * If this is called with aOpaque set to true, the caller is promising
+   * that by the end of this transaction the entire visible region
+   * (as specified by SetVisibleRegion) will be filled with opaque
+   * content. This enables some internal quality and performance
+   * optimizations.
    */
-  void SetContentFlags(PRUint32 aFlags)
+  void SetIsOpaqueContent(PRBool aOpaque)
   {
-    mContentFlags = aFlags;
+    mIsOpaqueContent = aOpaque;
     Mutated();
   }
   /**
    * CONSTRUCTION PHASE ONLY
    * Tell this layer which region will be visible. It is the responsibility
    * of the caller to ensure that content outside this region does not
    * contribute to the final visible window. This can be an
    * overapproximation to the true visible region.
@@ -524,17 +432,17 @@ public:
   {
     mTransform = aMatrix;
     Mutated();
   }
 
   // These getters can be used anytime.
   float GetOpacity() { return mOpacity; }
   const nsIntRect* GetClipRect() { return mUseClipRect ? &mClipRect : nsnull; }
-  PRUint32 GetContentFlags() { return mContentFlags; }
+  PRBool IsOpaqueContent() { return mIsOpaqueContent; }
   const nsIntRegion& GetVisibleRegion() { return mVisibleRegion; }
   ContainerLayer* GetParent() { return mParent; }
   Layer* GetNextSibling() { return mNextSibling; }
   Layer* GetPrevSibling() { return mPrevSibling; }
   virtual Layer* GetFirstChild() { return nsnull; }
   const gfx3DMatrix& GetTransform() { return mTransform; }
 
   /**
@@ -547,38 +455,20 @@ public:
 
   // Returns true if it's OK to save the contents of aLayer in an
   // opaque surface (a surface without an alpha channel).
   // If we can use a surface without an alpha channel, we should, because
   // it will often make painting of antialiased text faster and higher
   // quality.
   PRBool CanUseOpaqueSurface();
 
-  /**
-   * This setter can be used anytime. The user data for all keys is
-   * initially null. Ownership pases to the layer manager.
-   */
-  void SetUserData(void* aKey, LayerUserData* aData)
-  { mUserData.Set(aKey, aData); }
-  /**
-   * This can be used anytime. Ownership passes to the caller!
-   */
-  nsAutoPtr<LayerUserData> RemoveUserData(void* aKey)
-  { nsAutoPtr<LayerUserData> d(mUserData.Remove(aKey)); return d; }
-  /**
-   * This getter can be used anytime.
-   */
-  PRBool HasUserData(void* aKey)
-  { return mUserData.Has(aKey); }
-  /**
-   * This getter can be used anytime. Ownership is retained by the layer
-   * manager.
-   */
-  LayerUserData* GetUserData(void* aKey)
-  { return mUserData.Get(aKey); }
+  // This setter and getter can be used anytime. The user data is initially
+  // null.
+  void SetUserData(void* aData) { mUserData = aData; }
+  void* GetUserData() { return mUserData; }
 
   /**
    * Dynamic downcast to a Thebes layer. Returns null if this is not
    * a ThebesLayer.
    */
   virtual ThebesLayer* AsThebesLayer() { return nsnull; }
 
   virtual const char* Name() const =0;
@@ -624,42 +514,43 @@ public:
 
 protected:
   Layer(LayerManager* aManager, void* aImplData) :
     mManager(aManager),
     mParent(nsnull),
     mNextSibling(nsnull),
     mPrevSibling(nsnull),
     mImplData(aImplData),
+    mUserData(nsnull),
     mOpacity(1.0),
-    mContentFlags(0),
-    mUseClipRect(PR_FALSE)
+    mUseClipRect(PR_FALSE),
+    mIsOpaqueContent(PR_FALSE)
     {}
 
   void Mutated() { mManager->Mutated(this); }
 
   // Print interesting information about this into aTo.  Internally
   // used to implement Dump*() and Log*().  If subclasses have
   // additional interesting properties, they should override this with
   // an implementation that first calls the base implementation then
   // appends additional info to aTo.
   virtual nsACString& PrintInfo(nsACString& aTo, const char* aPrefix);
 
   LayerManager* mManager;
   ContainerLayer* mParent;
   Layer* mNextSibling;
   Layer* mPrevSibling;
   void* mImplData;
-  LayerUserDataSet mUserData;
+  void* mUserData;
   nsIntRegion mVisibleRegion;
   gfx3DMatrix mTransform;
   float mOpacity;
   nsIntRect mClipRect;
-  PRUint32 mContentFlags;
   PRPackedBool mUseClipRect;
+  PRPackedBool mIsOpaqueContent;
 };
 
 /**
  * A Layer which we can draw into using Thebes. It is a conceptually
  * infinite surface, but each ThebesLayer has an associated "valid region"
  * of contents that it is currently storing, which is finite. ThebesLayer
  * implementations can store content between paints.
  * 
--- a/gfx/layers/basic/BasicLayers.cpp
+++ b/gfx/layers/basic/BasicLayers.cpp
@@ -362,72 +362,53 @@ InheritContextFlags(gfxContext* aSource,
 {
   if (aSource->GetFlags() & gfxContext::FLAG_DESTINED_FOR_SCREEN) {
     aDest->SetFlag(gfxContext::FLAG_DESTINED_FOR_SCREEN);
   } else {
     aDest->ClearFlag(gfxContext::FLAG_DESTINED_FOR_SCREEN);
   }
 }
 
-static PRBool
-ShouldRetainTransparentSurface(PRUint32 aContentFlags,
-                               gfxASurface* aTargetSurface)
-{
-  if (aContentFlags & Layer::CONTENT_NO_TEXT)
-    return PR_TRUE;
-
-  switch (aTargetSurface->GetTextQualityInTransparentSurfaces()) {
-  case gfxASurface::TEXT_QUALITY_OK:
-    return PR_TRUE;
-  case gfxASurface::TEXT_QUALITY_OK_OVER_OPAQUE_PIXELS:
-    return (aContentFlags & Layer::CONTENT_NO_TEXT_OVER_TRANSPARENT) != 0;
-  default:
-    return PR_FALSE;
-  }
-}
-
 void
 BasicThebesLayer::Paint(gfxContext* aContext,
                         LayerManager::DrawThebesLayerCallback aCallback,
                         void* aCallbackData,
                         float aOpacity)
 {
   NS_ASSERTION(BasicManager()->InDrawing(),
                "Can only draw in drawing phase");
   gfxContext* target = BasicManager()->GetTarget();
   NS_ASSERTION(target, "We shouldn't be called if there's no target");
-  nsRefPtr<gfxASurface> targetSurface = aContext->CurrentSurface();
 
-  PRBool canUseOpaqueSurface = CanUseOpaqueSurface();
-  if (!BasicManager()->IsRetained() ||
-      (aOpacity == 1.0 && !canUseOpaqueSurface &&
-       !ShouldRetainTransparentSurface(mContentFlags, targetSurface))) {
-    mValidRegion.SetEmpty();
-    mBuffer.Clear();
-
+  if (!BasicManager()->IsRetained()) {
     if (aOpacity != 1.0) {
       target->Save();
       ClipToContain(target, mVisibleRegion.GetBounds());
       target->PushGroup(gfxASurface::CONTENT_COLOR_ALPHA);
     }
+    mValidRegion.SetEmpty();
+    mBuffer.Clear();
     aCallback(this, target, mVisibleRegion, nsIntRegion(), aCallbackData);
     if (aOpacity != 1.0) {
       target->PopGroupToSource();
       target->Paint(aOpacity);
       target->Restore();
     }
     return;
   }
 
+  nsRefPtr<gfxASurface> targetSurface = aContext->CurrentSurface();
+  PRBool isOpaqueContent =
+    (targetSurface->AreSimilarSurfacesSensitiveToContentType() &&
+     aOpacity == 1.0 &&
+     CanUseOpaqueSurface());
   {
-    PRBool opaqueBuffer = canUseOpaqueSurface &&
-      targetSurface->AreSimilarSurfacesSensitiveToContentType();
     Buffer::ContentType contentType =
-      opaqueBuffer ? gfxASurface::CONTENT_COLOR :
-                     gfxASurface::CONTENT_COLOR_ALPHA;
+      isOpaqueContent ? gfxASurface::CONTENT_COLOR :
+                        gfxASurface::CONTENT_COLOR_ALPHA;
     Buffer::PaintState state = mBuffer.BeginPaint(this, contentType);
     mValidRegion.Sub(mValidRegion, state.mRegionToInvalidate);
 
     if (state.mContext) {
       // The area that became invalid and is visible needs to be repainted
       // (this could be the whole visible area if our buffer switched
       // from RGB to RGBA, because we might need to repaint with
       // subpixel AA)
@@ -439,17 +420,17 @@ BasicThebesLayer::Paint(gfxContext* aCon
     } else {
       // It's possible that state.mRegionToInvalidate is nonempty here,
       // if we are shrinking the valid region to nothing.
       NS_ASSERTION(state.mRegionToDraw.IsEmpty(),
                    "If we need to draw, we should have a context");
     }
   }
 
-  mBuffer.DrawTo(this, canUseOpaqueSurface, target, aOpacity);
+  mBuffer.DrawTo(this, isOpaqueContent, target, aOpacity);
 }
 
 void
 BasicThebesLayerBuffer::DrawTo(ThebesLayer* aLayer,
                                PRBool aIsOpaqueContent,
                                gfxContext* aTarget,
                                float aOpacity)
 {
@@ -696,17 +677,17 @@ BasicCanvasLayer::Updated(const nsIntRec
   NS_ASSERTION(mUpdatedRect.IsEmpty(),
                "CanvasLayer::Updated called more than once in a transaction!");
 
   mUpdatedRect.UnionRect(mUpdatedRect, aRect);
 
   if (mGLContext) {
     nsRefPtr<gfxImageSurface> isurf =
       new gfxImageSurface(gfxIntSize(mBounds.width, mBounds.height),
-                          (GetContentFlags() & CONTENT_OPAQUE)
+                          IsOpaqueContent()
                             ? gfxASurface::ImageFormatRGB24
                             : gfxASurface::ImageFormatARGB32);
     if (!isurf || isurf->CairoStatus() != 0) {
       return;
     }
 
     NS_ASSERTION(isurf->Stride() == mBounds.width * 4, "gfxImageSurface stride isn't what we expect!");
 
@@ -807,17 +788,17 @@ ToOutsideIntRect(const gfxRect &aRect)
  * aDirtyVisibleRegionInContainer is filled in only if we return false.
  * It contains the union of the visible regions of leaf layers under aLayer.
  */
 static PRBool
 MayHaveOverlappingOrTransparentLayers(Layer* aLayer,
                                       const nsIntRect& aBounds,
                                       nsIntRegion* aDirtyVisibleRegionInContainer)
 {
-  if (!(aLayer->GetContentFlags() & Layer::CONTENT_OPAQUE)) {
+  if (!aLayer->IsOpaqueContent()) {
     return PR_TRUE;
   }
 
   gfxMatrix matrix;
   if (!aLayer->GetTransform().Is2D(&matrix) ||
       matrix.HasNonIntegerTranslation()) {
     return PR_TRUE;
   }
--- a/gfx/layers/d3d9/ThebesLayerD3D9.cpp
+++ b/gfx/layers/d3d9/ThebesLayerD3D9.cpp
@@ -41,16 +41,37 @@
 #include "gfxWindowsPlatform.h"
 #ifdef CAIRO_HAS_D2D_SURFACE
 #include "gfxD2DSurface.h"
 #endif
 
 namespace mozilla {
 namespace layers {
 
+// Returns true if it's OK to save the contents of aLayer in an
+// opaque surface (a surface without an alpha channel).
+// If we can use a surface without an alpha channel, we should, because
+// it will often make painting of antialiased text faster and higher
+// quality.
+static PRBool
+UseOpaqueSurface(Layer* aLayer)
+{
+  // If the visible content in the layer is opaque, there is no need
+  // for an alpha channel.
+  if (aLayer->IsOpaqueContent())
+    return PR_TRUE;
+  // Also, if this layer is the bottommost layer in a container which
+  // doesn't need an alpha channel, we can use an opaque surface for this
+  // layer too. Any transparent areas must be covered by something else
+  // in the container.
+  ContainerLayer* parent = aLayer->GetParent();
+  return parent && parent->GetFirstChild() == aLayer &&
+         UseOpaqueSurface(parent);
+}
+
 ThebesLayerD3D9::ThebesLayerD3D9(LayerManagerD3D9 *aManager)
   : ThebesLayer(aManager, NULL)
   , LayerD3D9(aManager)
 {
   mImplData = static_cast<LayerD3D9*>(this);
   aManager->deviceManager()->mThebesLayers.AppendElement(this);
 }
 
@@ -78,17 +99,17 @@ ThebesLayerD3D9::SetVisibleRegion(const 
 
   if (!mTexture) {
     // If we don't need to retain content initialize lazily. This is good also
     // because we might get mIsOpaqueSurface set later than the first call to
     // SetVisibleRegion.
     return;
   }
 
-  D3DFORMAT fmt = (CanUseOpaqueSurface() && !mD2DSurface) ?
+  D3DFORMAT fmt = (UseOpaqueSurface(this) && !mD2DSurface) ?
                     D3DFMT_X8R8G8B8 : D3DFMT_A8R8G8B8;
 
   D3DSURFACE_DESC desc;
   mTexture->GetLevelDesc(0, &desc);
 
   if (fmt != desc.Format) {
     // The new format isn't compatible with the old texture, toss out the old
     // texture.
@@ -172,17 +193,17 @@ ThebesLayerD3D9::RenderLayer()
   if (mVisibleRegion.IsEmpty()) {
     return;
   }
 
   nsIntRect visibleRect = mVisibleRegion.GetBounds();
 
   // We differentiate between these formats since D3D9 will only allow us to
   // call GetDC on an opaque surface.
-  D3DFORMAT fmt = (CanUseOpaqueSurface() && !mD2DSurface) ?
+  D3DFORMAT fmt = (UseOpaqueSurface(this) && !mD2DSurface) ?
                     D3DFMT_X8R8G8B8 : D3DFMT_A8R8G8B8;
 
   if (mTexture) {
     D3DSURFACE_DESC desc;
     mTexture->GetLevelDesc(0, &desc);
 
     if (fmt != desc.Format) {
       // The new format isn't compatible with the old texture, toss out the old
@@ -288,30 +309,30 @@ ThebesLayerD3D9::DrawRegion(const nsIntR
     // drawing in a seperate 'validation' iteration. And then flushing once for
     // all the D2D surfaces we might have drawn, before doing our D3D9 rendering
     // loop.
     cairo_d2d_finish_device(gfxWindowsPlatform::GetPlatform()->GetD2DDevice());
     return;
   }
 #endif
 
-  D3DFORMAT fmt = CanUseOpaqueSurface() ? D3DFMT_X8R8G8B8 : D3DFMT_A8R8G8B8;
+  D3DFORMAT fmt = UseOpaqueSurface(this) ? D3DFMT_X8R8G8B8 : D3DFMT_A8R8G8B8;
   nsIntRect bounds = aRegion.GetBounds();
 
   gfxASurface::gfxImageFormat imageFormat = gfxASurface::ImageFormatARGB32;
   nsRefPtr<gfxASurface> destinationSurface;
 
   nsRefPtr<IDirect3DTexture9> tmpTexture;
   device()->CreateTexture(bounds.width, bounds.height, 1,
                           0, fmt,
                           D3DPOOL_SYSTEMMEM, getter_AddRefs(tmpTexture), NULL);
 
   nsRefPtr<IDirect3DSurface9> surf;
   HDC dc;
-  if (CanUseOpaqueSurface()) {
+  if (UseOpaqueSurface(this)) {
     hr = tmpTexture->GetSurfaceLevel(0, getter_AddRefs(surf));
 
     if (FAILED(hr)) {
       // Uh-oh, bail.
       NS_WARNING("Failed to get texture surface level.");
       return;
     }
 
@@ -334,17 +355,17 @@ ThebesLayerD3D9::DrawRegion(const nsIntR
                              imageFormat);
   }
 
   context = new gfxContext(destinationSurface);
   context->Translate(gfxPoint(-bounds.x, -bounds.y));
   LayerManagerD3D9::CallbackInfo cbInfo = mD3DManager->GetCallbackInfo();
   cbInfo.Callback(this, context, aRegion, nsIntRegion(), cbInfo.CallbackData);
 
-  if (CanUseOpaqueSurface()) {
+  if (UseOpaqueSurface(this)) {
     surf->ReleaseDC(dc);
   } else {
     D3DLOCKED_RECT r;
     tmpTexture->LockRect(0, &r, NULL, 0);
 
     nsRefPtr<gfxImageSurface> imgSurface =
     new gfxImageSurface((unsigned char *)r.pBits,
                         gfxIntSize(bounds.width,
@@ -397,28 +418,28 @@ ThebesLayerD3D9::CreateNewTexture(const 
       gfxWindowsPlatform::RENDER_DIRECT2D) {
         if (mD3DManager->deviceManager()->IsD3D9Ex()) {
           // We should have D3D9Ex where we have D2D.
           HANDLE sharedHandle = 0;
           device()->CreateTexture(aSize.width, aSize.height, 1,
                                   D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8,
                                   D3DPOOL_DEFAULT, getter_AddRefs(mTexture), &sharedHandle);
 
-          mD2DSurface = new gfxD2DSurface(sharedHandle, CanUseOpaqueSurface() ?
+          mD2DSurface = new gfxD2DSurface(sharedHandle, UseOpaqueSurface(this) ?
             gfxASurface::CONTENT_COLOR : gfxASurface::CONTENT_COLOR_ALPHA);
 
           // If there's an error, go on and do what we always do.
           if (mD2DSurface->CairoStatus()) {
             mD2DSurface = nsnull;
             mTexture = nsnull;
           }
         }
   }
 #endif
   if (!mTexture) {
     device()->CreateTexture(aSize.width, aSize.height, 1,
-                            D3DUSAGE_RENDERTARGET, CanUseOpaqueSurface() ? D3DFMT_X8R8G8B8 : D3DFMT_A8R8G8B8,
+                            D3DUSAGE_RENDERTARGET, UseOpaqueSurface(this) ? D3DFMT_X8R8G8B8 : D3DFMT_A8R8G8B8,
                             D3DPOOL_DEFAULT, getter_AddRefs(mTexture), NULL);
   }
 }
 
 } /* namespace layers */
 } /* namespace mozilla */
--- a/gfx/layers/ipc/PLayers.ipdl
+++ b/gfx/layers/ipc/PLayers.ipdl
@@ -88,17 +88,17 @@ struct OpCreateImageBuffer {
   nsIntSize size;
   Shmem initialFront;
 };
 
 // Change a layer's attributes
 struct CommonLayerAttributes {
   nsIntRegion visibleRegion;
   gfx3DMatrix transform;
-  PRUint32 contentFlags;
+  bool isOpaqueContent;
   float opacity;
   bool useClipRect;
   nsIntRect clipRect;
 };
 
 struct ThebesLayerAttributes   { nsIntRegion validRegion; };
 struct ColorLayerAttributes    { gfxRGBA color; };
 struct CanvasLayerAttributes   { GraphicsFilterType filter; };
--- a/gfx/layers/ipc/ShadowLayers.cpp
+++ b/gfx/layers/ipc/ShadowLayers.cpp
@@ -266,17 +266,17 @@ ShadowLayerForwarder::EndTransaction(nsT
     ShadowableLayer* shadow = *it;
     Layer* mutant = shadow->AsLayer();
     NS_ABORT_IF_FALSE(!!mutant, "unshadowable layer?");
 
     LayerAttributes attrs;
     CommonLayerAttributes& common = attrs.common();
     common.visibleRegion() = mutant->GetVisibleRegion();
     common.transform() = mutant->GetTransform();
-    common.contentFlags() = mutant->GetContentFlags();
+    common.isOpaqueContent() = mutant->IsOpaqueContent();
     common.opacity() = mutant->GetOpacity();
     common.useClipRect() = !!mutant->GetClipRect();
     common.clipRect() = (common.useClipRect() ?
                          *mutant->GetClipRect() : nsIntRect());
     attrs.specific() = null_t();
     mutant->FillSpecificAttributes(attrs.specific());
 
     mTxn->AddEdit(OpSetLayerAttributes(NULL, Shadow(shadow), attrs));
--- a/gfx/layers/ipc/ShadowLayersParent.cpp
+++ b/gfx/layers/ipc/ShadowLayersParent.cpp
@@ -224,17 +224,17 @@ ShadowLayersParent::RecvUpdate(const nsT
       MOZ_LAYERS_LOG(("[ParentSide] SetLayerAttributes"));
 
       const OpSetLayerAttributes& osla = edit.get_OpSetLayerAttributes();
       Layer* layer = AsShadowLayer(osla)->AsLayer();
       const LayerAttributes& attrs = osla.attrs();
 
       const CommonLayerAttributes& common = attrs.common();
       layer->SetVisibleRegion(common.visibleRegion());
-      layer->SetContentFlags(common.contentFlags());
+      layer->SetIsOpaqueContent(common.isOpaqueContent());
       layer->SetOpacity(common.opacity());
       layer->SetClipRect(common.useClipRect() ? &common.clipRect() : NULL);
       layer->SetTransform(common.transform());
 
       typedef SpecificLayerAttributes Specific;
       const SpecificLayerAttributes& specific = attrs.specific();
       switch (specific.type()) {
       case Specific::Tnull_t:
--- a/gfx/thebes/gfxASurface.h
+++ b/gfx/thebes/gfxASurface.h
@@ -148,50 +148,17 @@ public:
      * false if they don't (i.e. the surface returned by
      * CreateOffscreenSurface is always as if you passed
      * CONTENT_COLOR_ALPHA). Knowing this can be useful to avoid
      * recreating a surface just because it changed from opaque to
      * transparent.
      */
     virtual PRBool AreSimilarSurfacesSensitiveToContentType()
     {
-        return PR_TRUE;
-    }
-
-    enum TextQuality {
-        /**
-         * TEXT_QUALITY_OK means that text is always rendered to a
-         * transparent surface just as well as it would be rendered to an
-         * opaque surface. This would normally only be true if
-         * subpixel antialiasing is disabled or if the platform's
-         * transparent surfaces support component alpha.
-         */
-        TEXT_QUALITY_OK,
-        /**
-         * TEXT_QUALITY_OK_OVER_OPAQUE_PIXELS means that text is rendered
-         * to a transparent surface just as well as it would be rendered to an
-         * opaque surface, but only if all the pixels the text is drawn
-         * over already have opaque alpha values.
-         */
-        TEXT_QUALITY_OK_OVER_OPAQUE_PIXELS,
-        /**
-         * TEXT_QUALITY_BAD means that text is rendered
-         * to a transparent surface worse than it would be rendered to an
-         * opaque surface, even if all the pixels the text is drawn
-         * over already have opaque alpha values.
-         */
-        TEXT_QUALITY_BAD
-    };
-    /**
-     * Determine how well text would be rendered in transparent surfaces that
-     * are similar to this surface.
-     */
-    virtual TextQuality GetTextQualityInTransparentSurfaces()
-    {
-        return TEXT_QUALITY_BAD;
+      return PR_TRUE;
     }
 
     int CairoStatus();
 
     /* Make sure that the given dimensions don't overflow a 32-bit signed int
      * using 4 bytes per pixel; optionally, make sure that either dimension
      * doesn't exceed the given limit.
      */
--- a/gfx/thebes/gfxD2DSurface.h
+++ b/gfx/thebes/gfxD2DSurface.h
@@ -52,22 +52,16 @@ public:
                   gfxImageFormat imageFormat = ImageFormatRGB24);
 
     gfxD2DSurface(HANDLE handle, gfxContentType aContent);
 
     gfxD2DSurface(cairo_surface_t *csurf);
 
     virtual ~gfxD2DSurface();
 
-    virtual TextQuality GetTextQualityInTransparentSurfaces()
-    {
-      // D2D always draws text in transparent surfaces with grayscale-AA,
-      // even if the text is over opaque pixels.
-      return TEXT_QUALITY_BAD;
-    }
 
     void Present();
     void Scroll(const nsIntPoint &aDelta, const nsIntRect &aClip);
 
     HDC GetDC(PRBool aRetainContents);
     void ReleaseDC(const nsIntRect *aUpdatedRect);
 };
 
--- a/gfx/thebes/gfxQuartzSurface.h
+++ b/gfx/thebes/gfxQuartzSurface.h
@@ -55,20 +55,16 @@ public:
     virtual ~gfxQuartzSurface();
 
     virtual already_AddRefed<gfxASurface> CreateSimilarSurface(gfxContentType aType,
                                                                const gfxIntSize& aSize);
     virtual PRBool AreSimilarSurfacesSensitiveToContentType()
     {
       return PR_FALSE;
     }
-    virtual TextQuality GetTextQualityInTransparentSurfaces()
-    {
-      return TEXT_QUALITY_OK_OVER_OPAQUE_PIXELS;
-    }
 
     const gfxSize& GetSize() const { return mSize; }
 
     CGContextRef GetCGContext() { return mCGContext; }
 
     CGContextRef GetCGContextWithClip(gfxContext *ctx);
 
     virtual PRInt32 GetDefaultContextFlags() const;
--- a/gfx/thebes/gfxWindowsSurface.h
+++ b/gfx/thebes/gfxWindowsSurface.h
@@ -76,21 +76,16 @@ public:
     HDC GetDCWithClip(gfxContext *);
 
     already_AddRefed<gfxImageSurface> GetImageSurface();
 
     already_AddRefed<gfxWindowsSurface> OptimizeToDDB(HDC dc,
                                                       const gfxIntSize& size,
                                                       gfxImageFormat format);
 
-    virtual TextQuality GetTextQualityInTransparentSurfaces()
-    {
-      return TEXT_QUALITY_OK_OVER_OPAQUE_PIXELS;
-    }
-
     nsresult BeginPrinting(const nsAString& aTitle, const nsAString& aPrintToFileName);
     nsresult EndPrinting();
     nsresult AbortPrinting();
     nsresult BeginPage();
     nsresult EndPage();
 
     virtual PRInt32 GetDefaultContextFlags() const;
 
--- a/gfx/thebes/gfxXlibSurface.h
+++ b/gfx/thebes/gfxXlibSurface.h
@@ -72,21 +72,16 @@ public:
     Create(Screen* screen, XRenderPictFormat *format, const gfxIntSize& size,
            Drawable relatedDrawable = None);
 
     virtual ~gfxXlibSurface();
 
     virtual already_AddRefed<gfxASurface>
     CreateSimilarSurface(gfxContentType aType, const gfxIntSize& aSize);
 
-    virtual TextQuality GetTextQualityInTransparentSurfaces()
-    {
-      return TEXT_QUALITY_OK_OVER_OPAQUE_PIXELS;
-    }
-
     const gfxIntSize& GetSize() { return mSize; }
 
     Display* XDisplay() { return mDisplay; }
     Drawable XDrawable() { return mDrawable; }
 
     static int DepthOfVisual(const Screen* screen, const Visual* visual);
     static Visual* FindVisual(Screen* screen, gfxImageFormat format);
     static XRenderPictFormat *FindRenderFormat(Display *dpy, gfxImageFormat format);
--- a/layout/base/FrameLayerBuilder.cpp
+++ b/layout/base/FrameLayerBuilder.cpp
@@ -52,32 +52,24 @@ using namespace mozilla::layers;
 
 namespace mozilla {
 
 namespace {
 
 /**
  * This is the userdata we associate with a layer manager.
  */
-class LayerManagerData : public LayerUserData {
+class LayerManagerData {
 public:
   LayerManagerData() :
     mInvalidateAllThebesContent(PR_FALSE),
     mInvalidateAllLayers(PR_FALSE)
   {
-    MOZ_COUNT_CTOR(LayerManagerData);
     mFramesWithLayers.Init();
   }
-  ~LayerManagerData() {
-    // Remove display item data properties now, since we won't be able
-    // to find these frames again without mFramesWithLayers.
-    mFramesWithLayers.EnumerateEntries(
-        FrameLayerBuilder::RemoveDisplayItemDataForFrame, nsnull);
-    MOZ_COUNT_DTOR(LayerManagerData);
-  }
 
   /**
    * Tracks which frames have layers associated with them.
    */
   nsTHashtable<nsPtrHashKey<nsIFrame> > mFramesWithLayers;
   PRPackedBool mInvalidateAllThebesContent;
   PRPackedBool mInvalidateAllLayers;
 };
@@ -154,35 +146,34 @@ protected:
    * ThebesLayer in z-order. This reduces the number of layers and
    * makes it more likely a display item will be rendered to an opaque
    * layer, giving us the best chance of getting subpixel AA.
    */
   class ThebesLayerData {
   public:
     ThebesLayerData() :
       mActiveScrolledRoot(nsnull), mLayer(nsnull),
-      mIsSolidColorInVisibleRegion(PR_FALSE),
-      mHasText(PR_FALSE), mHasTextOverTransparent(PR_FALSE) {}
+      mIsSolidColorInVisibleRegion(PR_FALSE) {}
     /**
      * Record that an item has been added to the ThebesLayer, so we
      * need to update our regions.
      * @param aVisibleRect the area of the item that's visible
      * @param aDrawRect the area of the item that would be drawn if it
      * was completely visible
      * @param aOpaqueRect if non-null, the area of the item that's opaque.
      * We pass in a separate opaque rect because the opaque rect can be
      * bigger than the visible rect, and we want to have the biggest
      * opaque rect that we can.
      * @param aSolidColor if non-null, the visible area of the item is
      * a constant color given by *aSolidColor
      */
-    void Accumulate(nsDisplayListBuilder* aBuilder,
-                    nsDisplayItem* aItem,
-                    const nsIntRect& aVisibleRect,
-                    const nsIntRect& aDrawRect);
+    void Accumulate(const nsIntRect& aVisibleRect,
+                    const nsIntRect& aDrawRect,
+                    const nsIntRect* aOpaqueRect,
+                    nscolor* aSolidColor);
     nsIFrame* GetActiveScrolledRoot() { return mActiveScrolledRoot; }
 
     /**
      * The region of visible content in the layer, relative to the
      * container layer (which is at the snapped top-left of the display
      * list reference frame).
      */
     nsIntRegion  mVisibleRegion;
@@ -224,25 +215,16 @@ protected:
      * If mIsSolidColorInVisibleRegion is true, this is the color of the visible
      * region.
      */
     nscolor      mSolidColor;
     /**
      * True if every pixel in mVisibleRegion will have color mSolidColor.
      */
     PRPackedBool mIsSolidColorInVisibleRegion;
-    /**
-     * True if there is any text visible in the layer.
-     */
-    PRPackedBool mHasText;
-    /**
-     * True if there is any text visible in the layer that's over
-     * transparent pixels in the layer.
-     */
-    PRPackedBool mHasTextOverTransparent;
   };
 
   /**
    * Grab the next recyclable ThebesLayer, or create one if there are no
    * more recyclable ThebesLayers. Does any necessary invalidation of
    * a recycled ThebesLayer, and sets up the transform on the ThebesLayer
    * to account for scrolling.
    */
@@ -259,22 +241,16 @@ protected:
   void CollectOldLayers();
   /**
    * If aItem used to belong to a ThebesLayer, invalidates the area of
    * aItem in that layer. If aNewLayer is a ThebesLayer, invalidates the area of
    * aItem in that layer.
    */
   void InvalidateForLayerChange(nsDisplayItem* aItem, Layer* aNewLayer);
   /**
-   * Try to determine whether the ThebesLayer at aThebesLayerIndex
-   * has an opaque single color covering the visible area behind it.
-   * If successful, return that color, otherwise return NS_RGBA(0,0,0,0).
-   */
-  nscolor FindOpaqueBackgroundColorFor(PRInt32 aThebesLayerIndex);
-  /**
    * Indicate that we are done adding items to the ThebesLayer at the top of
    * mThebesLayerDataStack. Set the final visible region and opaque-content
    * flag, and pop it off the stack.
    */
   void PopThebesLayerData();
   /**
    * Find the ThebesLayer to which we should assign the next display item.
    * We scan the ThebesLayerData stack to find the topmost ThebesLayer
@@ -287,20 +263,21 @@ protected:
    * ThebesLayerData stack, later elements on the stack will be popped off.
    * @param aVisibleRect the area of the next display item that's visible
    * @param aActiveScrolledRoot the active scrolled root for the next
    * display item
    * @param aOpaqueRect if non-null, a region of the display item that is opaque
    * @param aSolidColor if non-null, indicates that every pixel in aVisibleRect
    * will be painted with aSolidColor by the item
    */
-  already_AddRefed<ThebesLayer> FindThebesLayerFor(nsDisplayItem* aItem,
-                                                   const nsIntRect& aVisibleRect,
+  already_AddRefed<ThebesLayer> FindThebesLayerFor(const nsIntRect& aVisibleRect,
                                                    const nsIntRect& aDrawRect,
-                                                   nsIFrame* aActiveScrolledRoot);
+                                                   nsIFrame* aActiveScrolledRoot,
+                                                   const nsIntRect* aOpaqueRect,
+                                                   nscolor* aSolidColor);
   ThebesLayerData* GetTopThebesLayerData()
   {
     return mThebesLayerDataStack.IsEmpty() ? nsnull
         : mThebesLayerDataStack[mThebesLayerDataStack.Length() - 1].get();
   }
 
   nsDisplayListBuilder*            mBuilder;
   LayerManager*                    mManager;
@@ -320,47 +297,30 @@ protected:
   nsAutoTArray<nsRefPtr<Layer>,1>  mNewChildLayers;
   nsTArray<nsRefPtr<ThebesLayer> > mRecycledThebesLayers;
   nsTArray<nsRefPtr<ColorLayer> >  mRecycledColorLayers;
   PRUint32                         mNextFreeRecycledThebesLayer;
   PRUint32                         mNextFreeRecycledColorLayer;
   PRPackedBool                     mInvalidateAllThebesContent;
 };
 
-class ThebesDisplayItemLayerUserData : public LayerUserData
-{
-public:
-  ThebesDisplayItemLayerUserData() :
-    mForcedBackgroundColor(NS_RGBA(0,0,0,0)) {}
-
-  nscolor mForcedBackgroundColor;
-};
-
 /**
  * The address of gThebesDisplayItemLayerUserData is used as the user
- * data key for ThebesLayers created by FrameLayerBuilder.
+ * data pointer for ThebesLayers created by FrameLayerBuilder.
  * It identifies ThebesLayers used to draw non-layer content, which are
  * therefore eligible for recycling. We want display items to be able to
  * create their own dedicated ThebesLayers in BuildLayer, if necessary,
  * and we wouldn't want to accidentally recycle those.
- * The user data is a ThebesDisplayItemLayerUserData.
  */
-PRUint8 gThebesDisplayItemLayerUserData;
+static PRUint8 gThebesDisplayItemLayerUserData;
 /**
  * The address of gColorLayerUserData is used as the user
- * data key for ColorLayers created by FrameLayerBuilder.
- * The user data is null.
+ * data pointer for ColorLayers
  */
-PRUint8 gColorLayerUserData;
-/**
- * The address of gLayerManagerUserData is used as the user
- * data key for retained LayerManagers managed by FrameLayerBuilder.
- * The user data is a LayerManagerData.
- */
-PRUint8 gLayerManagerUserData;
+static PRUint8 gColorLayerUserData;
 
 } // anonymous namespace
 
 PRBool
 FrameLayerBuilder::DisplayItemDataEntry::HasContainerLayer()
 {
   for (PRUint32 i = 0; i < mData.Length(); ++i) {
     if (mData[i].mLayer->GetType() == Layer::TYPE_CONTAINER)
@@ -377,21 +337,22 @@ FrameLayerBuilder::InternalDestroyDispla
   nsRefPtr<LayerManager> managerRef;
   nsTArray<DisplayItemData>* array =
     reinterpret_cast<nsTArray<DisplayItemData>*>(&aPropertyValue);
   NS_ASSERTION(!array->IsEmpty(), "Empty arrays should not be stored");
 
   if (aRemoveFromFramesWithLayers) {
     LayerManager* manager = array->ElementAt(0).mLayer->Manager();
     LayerManagerData* data = static_cast<LayerManagerData*>
-      (manager->GetUserData(&gLayerManagerUserData));
+      (manager->GetUserData());
     NS_ASSERTION(data, "Frame with layer should have been recorded");
     data->mFramesWithLayers.RemoveEntry(aFrame);
     if (data->mFramesWithLayers.Count() == 0) {
-      manager->RemoveUserData(&gLayerManagerUserData);
+      delete data;
+      manager->SetUserData(nsnull);
       // Consume the reference we added when we set the user data
       // in DidEndTransaction. But don't actually release until we've
       // released all the layers in the DisplayItemData array below!
       managerRef = manager;
       NS_RELEASE(manager);
     }
   }
 
@@ -405,17 +366,17 @@ FrameLayerBuilder::DestroyDisplayItemDat
   InternalDestroyDisplayItemData(aFrame, aPropertyValue, PR_TRUE);
 }
 
 void
 FrameLayerBuilder::WillBeginRetainedLayerTransaction(LayerManager* aManager)
 {
   mRetainingManager = aManager;
   LayerManagerData* data = static_cast<LayerManagerData*>
-    (aManager->GetUserData(&gLayerManagerUserData));
+    (aManager->GetUserData());
   if (data) {
     mInvalidateAllThebesContent = data->mInvalidateAllThebesContent;
     mInvalidateAllLayers = data->mInvalidateAllLayers;
   }
 }
 
 /**
  * A helper function to remove the mThebesLayerItems entries for every
@@ -454,23 +415,23 @@ FrameLayerBuilder::WillEndTransaction(La
     return;
 
   // We need to save the data we'll need to support retaining. We do this
   // before we paint so that invalidation triggered by painting will
   // be able to update the ThebesLayerInvalidRegionProperty values
   // correctly and the NS_FRAME_HAS_CONTAINER_LAYER bits will be set
   // correctly.
   LayerManagerData* data = static_cast<LayerManagerData*>
-    (mRetainingManager->GetUserData(&gLayerManagerUserData));
+    (mRetainingManager->GetUserData());
   if (data) {
     // Update all the frames that used to have layers.
     data->mFramesWithLayers.EnumerateEntries(UpdateDisplayItemDataForFrame, this);
   } else {
     data = new LayerManagerData();
-    mRetainingManager->SetUserData(&gLayerManagerUserData, data);
+    mRetainingManager->SetUserData(data);
     // Addref mRetainingManager. We'll release it when 'data' is
     // removed.
     NS_ADDREF(mRetainingManager);
   }
   // Now go through all the frames that didn't have any retained
   // display items before, and record those retained display items.
   // This also empties mNewDisplayItemData.
   mNewDisplayItemData.EnumerateEntries(StoreNewDisplayItemData, data);
@@ -484,17 +445,17 @@ FrameLayerBuilder::WillEndTransaction(La
 /* static */ PLDHashOperator
 FrameLayerBuilder::UpdateDisplayItemDataForFrame(nsPtrHashKey<nsIFrame>* aEntry,
                                                  void* aUserArg)
 {
   FrameLayerBuilder* builder = static_cast<FrameLayerBuilder*>(aUserArg);
   nsIFrame* f = aEntry->GetKey();
   FrameProperties props = f->Properties();
   DisplayItemDataEntry* newDisplayItems =
-    builder ? builder->mNewDisplayItemData.GetEntry(f) : nsnull;
+    builder->mNewDisplayItemData.GetEntry(f);
   if (!newDisplayItems) {
     // This frame was visible, but isn't anymore.
     PRBool found;
     void* prop = props.Remove(DisplayItemDataProperty(), &found);
     NS_ASSERTION(found, "How can the frame property be missing?");
     // Pass PR_FALSE to not remove from mFramesWithLayers, we'll remove it
     // by returning PL_DHASH_REMOVE below.
     // Note that DestroyDisplayItemData would delete the user data
@@ -629,17 +590,17 @@ ContainerState::CreateOrRecycleColorLaye
     // reapply any necessary clipping.
     layer->SetClipRect(nsnull);
   } else {
     // Create a new layer
     layer = mManager->CreateColorLayer();
     if (!layer)
       return nsnull;
     // Mark this layer as being used for Thebes-painting display items
-    layer->SetUserData(&gColorLayerUserData, nsnull);
+    layer->SetUserData(&gColorLayerUserData);
   }
   return layer.forget();
 }
 
 already_AddRefed<ThebesLayer>
 ContainerState::CreateOrRecycleThebesLayer(nsIFrame* aActiveScrolledRoot)
 {
   // We need a new thebes layer
@@ -671,18 +632,17 @@ ContainerState::CreateOrRecycleThebesLay
     // InvalidateAllThebesLayerContents has ensured
     // the area is invalidated in the widget.
   } else {
     // Create a new thebes layer
     layer = mManager->CreateThebesLayer();
     if (!layer)
       return nsnull;
     // Mark this layer as being used for Thebes-painting display items
-    layer->SetUserData(&gThebesDisplayItemLayerUserData,
-        new ThebesDisplayItemLayerUserData());
+    layer->SetUserData(&gThebesDisplayItemLayerUserData);
   }
 
   // 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);
   nsIntPoint pixOffset = offset.ToNearestPixels(
       aActiveScrolledRoot->PresContext()->AppUnitsPerDevPixel());
   gfxMatrix matrix;
@@ -732,57 +692,39 @@ SetVisibleRectForLayer(Layer* aLayer, co
       NS_WARNING("Visible rect transformed out of bounds");
     }
     aLayer->SetVisibleRegion(visibleRect);
   } else {
     NS_ERROR("Only 2D transformations currently supported");
   }
 }
 
-nscolor
-ContainerState::FindOpaqueBackgroundColorFor(PRInt32 aThebesLayerIndex)
-{
-  ThebesLayerData* target = mThebesLayerDataStack[aThebesLayerIndex];
-  for (PRInt32 i = aThebesLayerIndex - 1; i >= 0; --i) {
-    ThebesLayerData* candidate = mThebesLayerDataStack[i];
-    nsIntRegion visibleAboveIntersection;
-    visibleAboveIntersection.And(candidate->mVisibleAboveRegion, target->mVisibleRegion);
-    if (!visibleAboveIntersection.IsEmpty()) {
-      // Some non-Thebes content between target and candidate; this is
-      // hopeless
-      break;
-    }
-
-    nsIntRegion intersection;
-    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);
-    return mBuilder->LayerBuilder()->
-      FindOpaqueColorCovering(mBuilder, candidate->mLayer, rect);
-  }
-  return NS_RGBA(0,0,0,0);
-}
-
 void
 ContainerState::PopThebesLayerData()
 {
   NS_ASSERTION(!mThebesLayerDataStack.IsEmpty(), "Can't pop");
 
   PRInt32 lastIndex = mThebesLayerDataStack.Length() - 1;
   ThebesLayerData* data = mThebesLayerDataStack[lastIndex];
 
+  if (lastIndex > 0) {
+    // Since we're going to pop off the last ThebesLayerData, the
+    // mVisibleAboveRegion of the second-to-last item will need to include
+    // the regions of the last item.
+    ThebesLayerData* nextData = mThebesLayerDataStack[lastIndex - 1];
+    nextData->mVisibleAboveRegion.Or(nextData->mVisibleAboveRegion,
+                                     data->mVisibleAboveRegion);
+    nextData->mVisibleAboveRegion.Or(nextData->mVisibleAboveRegion,
+                                     data->mVisibleRegion);
+    nextData->mDrawAboveRegion.Or(nextData->mDrawAboveRegion,
+                                     data->mDrawAboveRegion);
+    nextData->mDrawAboveRegion.Or(nextData->mDrawAboveRegion,
+                                     data->mDrawRegion);
+  }
+
   Layer* layer;
   if (data->mIsSolidColorInVisibleRegion) {
     nsRefPtr<ColorLayer> colorLayer = CreateOrRecycleColorLayer();
     colorLayer->SetColor(data->mSolidColor);
 
     NS_ASSERTION(!mNewChildLayers.Contains(colorLayer), "Layer already in list???");
     nsTArray_base::index_type index = mNewChildLayers.IndexOf(data->mLayer);
     NS_ASSERTION(index != nsTArray_base::NoIndex, "Thebes layer not found?");
@@ -819,133 +761,67 @@ ContainerState::PopThebesLayerData()
     rgn.MoveBy(-nsIntPoint(PRInt32(transform.x0), PRInt32(transform.y0)));
     layer->SetVisibleRegion(rgn);
   } else {
     NS_ERROR("Only 2D transformations currently supported");
   }
 
   nsIntRegion transparentRegion;
   transparentRegion.Sub(data->mVisibleRegion, data->mOpaqueRegion);
-  PRBool isOpaque = transparentRegion.IsEmpty();
-  // For translucent ThebesLayers, try to find an opaque background
-  // color that covers the entire area beneath it so we can pull that
-  // color into this layer to make it opaque.
-  if (layer == data->mLayer) {
-    nscolor backgroundColor = NS_RGBA(0,0,0,0);
-    if (!isOpaque) {
-      backgroundColor = FindOpaqueBackgroundColorFor(lastIndex);
-      if (NS_GET_A(backgroundColor) == 255) {
-        isOpaque = PR_TRUE;
-      }
-    }
-
-    // Store the background color
-    ThebesDisplayItemLayerUserData* userData =
-      static_cast<ThebesDisplayItemLayerUserData*>
-        (data->mLayer->GetUserData(&gThebesDisplayItemLayerUserData));
-    NS_ASSERTION(userData, "where did our user data go?");
-    if (userData->mForcedBackgroundColor != backgroundColor) {
-      // Invalidate the entire target ThebesLayer since we're changing
-      // the background color
-      data->mLayer->InvalidateRegion(data->mLayer->GetValidRegion());
-    }
-    userData->mForcedBackgroundColor = backgroundColor;
-  }
-  PRUint32 flags =
-    (isOpaque ? Layer::CONTENT_OPAQUE : 0) |
-    (data->mHasText ? 0 : Layer::CONTENT_NO_TEXT) |
-    (data->mHasTextOverTransparent ? 0 : Layer::CONTENT_NO_TEXT_OVER_TRANSPARENT);
-  layer->SetContentFlags(flags);
-
-  if (lastIndex > 0) {
-    // Since we're going to pop off the last ThebesLayerData, the
-    // mVisibleAboveRegion of the second-to-last item will need to include
-    // the regions of the last item.
-    ThebesLayerData* nextData = mThebesLayerDataStack[lastIndex - 1];
-    nextData->mVisibleAboveRegion.Or(nextData->mVisibleAboveRegion,
-                                     data->mVisibleAboveRegion);
-    nextData->mVisibleAboveRegion.Or(nextData->mVisibleAboveRegion,
-                                     data->mVisibleRegion);
-    nextData->mDrawAboveRegion.Or(nextData->mDrawAboveRegion,
-                                     data->mDrawAboveRegion);
-    nextData->mDrawAboveRegion.Or(nextData->mDrawAboveRegion,
-                                     data->mDrawRegion);
-  }
+  layer->SetIsOpaqueContent(transparentRegion.IsEmpty());
 
   mThebesLayerDataStack.RemoveElementAt(lastIndex);
 }
 
-static PRBool
-IsText(nsDisplayItem* aItem) {
-  switch (aItem->GetType()) {
-  case nsDisplayItem::TYPE_TEXT:
-  case nsDisplayItem::TYPE_BULLET:
-  case nsDisplayItem::TYPE_HEADER_FOOTER:
-  case nsDisplayItem::TYPE_MATHML_CHAR_FOREGROUND:
-#ifdef MOZ_XUL
-  case nsDisplayItem::TYPE_XUL_TEXT_BOX:
-#endif
-    return PR_TRUE;
-  default:
-    return PR_FALSE;
-  }
-}
-
 void
-ContainerState::ThebesLayerData::Accumulate(nsDisplayListBuilder* aBuilder,
-                                            nsDisplayItem* aItem,
-                                            const nsIntRect& aVisibleRect,
-                                            const nsIntRect& aDrawRect)
+ContainerState::ThebesLayerData::Accumulate(const nsIntRect& aVisibleRect,
+                                            const nsIntRect& aDrawRect,
+                                            const nsIntRect* aOpaqueRect,
+                                            nscolor* aSolidColor)
 {
-  nscolor uniformColor;
-  if (aItem->IsUniform(aBuilder, &uniformColor)) {
+  if (aSolidColor) {
     if (mVisibleRegion.IsEmpty()) {
       // This color is all we have
-      mSolidColor = uniformColor;
+      mSolidColor = *aSolidColor;
       mIsSolidColorInVisibleRegion = PR_TRUE;
     } else if (mIsSolidColorInVisibleRegion &&
                mVisibleRegion.IsEqual(nsIntRegion(aVisibleRect))) {
       // we can just blend the colors together
-      mSolidColor = NS_ComposeColors(mSolidColor, uniformColor);
+      mSolidColor = NS_ComposeColors(mSolidColor, *aSolidColor);
     } else {
       mIsSolidColorInVisibleRegion = PR_FALSE;
     }
   } else {
     mIsSolidColorInVisibleRegion = PR_FALSE;
   }
 
   mVisibleRegion.Or(mVisibleRegion, aVisibleRect);
   mVisibleRegion.SimplifyOutward(4);
   mDrawRegion.Or(mDrawRegion, aDrawRect);
   mDrawRegion.SimplifyOutward(4);
-
-  if (aItem->IsOpaque(aBuilder)) {
+  if (aOpaqueRect) {
     // 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.
     nsIntRegion tmp;
-    tmp.Or(mOpaqueRegion, aDrawRect);
+    tmp.Or(mOpaqueRegion, *aOpaqueRect);
     if (tmp.GetNumRects() <= 4) {
       mOpaqueRegion = tmp;
     }
-  } else if (IsText(aItem)) {
-    mHasText = PR_TRUE;
-    if (!mOpaqueRegion.Contains(aVisibleRect)) {
-      mHasTextOverTransparent = PR_TRUE;
-    }
   }
 }
 
 already_AddRefed<ThebesLayer>
-ContainerState::FindThebesLayerFor(nsDisplayItem* aItem,
-                                   const nsIntRect& aVisibleRect,
+ContainerState::FindThebesLayerFor(const nsIntRect& aVisibleRect,
                                    const nsIntRect& aDrawRect,
-                                   nsIFrame* aActiveScrolledRoot)
+                                   nsIFrame* aActiveScrolledRoot,
+                                   const nsIntRect* aOpaqueRect,
+                                   nscolor* aSolidColor)
 {
   PRInt32 i;
   PRInt32 lowestUsableLayerWithScrolledRoot = -1;
   PRInt32 topmostLayerWithScrolledRoot = -1;
   for (i = mThebesLayerDataStack.Length() - 1; i >= 0; --i) {
     ThebesLayerData* data = mThebesLayerDataStack[i];
     if (data->mDrawAboveRegion.Intersects(aVisibleRect)) {
       ++i;
@@ -989,17 +865,17 @@ ContainerState::FindThebesLayerFor(nsDis
     mThebesLayerDataStack.AppendElement(thebesLayerData);
     thebesLayerData->mLayer = layer;
     thebesLayerData->mActiveScrolledRoot = aActiveScrolledRoot;
   } else {
     thebesLayerData = mThebesLayerDataStack[lowestUsableLayerWithScrolledRoot];
     layer = thebesLayerData->mLayer;
   }
 
-  thebesLayerData->Accumulate(mBuilder, aItem, aVisibleRect, aDrawRect);
+  thebesLayerData->Accumulate(aVisibleRect, aDrawRect, aOpaqueRect, aSolidColor);
   return layer.forget();
 }
 
 static already_AddRefed<BasicLayerManager>
 BuildTempManagerForInactiveLayer(nsDisplayListBuilder* aBuilder,
                                  nsDisplayItem* aItem)
 {
   // This item has an inactive layer. We will render it to a ThebesLayer
@@ -1084,17 +960,17 @@ ContainerState::ProcessDisplayItems(cons
       nsRefPtr<Layer> ownLayer = item->BuildLayer(mBuilder, mManager);
       if (!ownLayer) {
         InvalidateForLayerChange(item, ownLayer);
         continue;
       }
 
       // Update that layer's clip and visible rects.
       NS_ASSERTION(ownLayer->Manager() == mManager, "Wrong manager");
-      NS_ASSERTION(!ownLayer->HasUserData(&gLayerManagerUserData),
+      NS_ASSERTION(ownLayer->GetUserData() != &gThebesDisplayItemLayerUserData,
                    "We shouldn't have a FrameLayerBuilder-managed layer here!");
       // It has its own layer. Update that layer's clip and visible rects.
       if (aClipRect) {
         ownLayer->IntersectClipRect(
             aClipRect->ToNearestPixels(appUnitsPerDevPixel));
       }
       ThebesLayerData* data = GetTopThebesLayerData();
       if (data) {
@@ -1135,19 +1011,27 @@ ContainerState::ProcessDisplayItems(cons
         // nsGfxScrollFrame will not repaint this item when scrolling occurs.
         nsIFrame* viewportFrame =
           nsLayoutUtils::GetClosestFrameOfType(f, nsGkAtoms::viewportFrame);
         NS_ASSERTION(viewportFrame, "no viewport???");
         activeScrolledRoot =
           nsLayoutUtils::GetActiveScrolledRootFor(viewportFrame, mBuilder->ReferenceFrame());
       }
 
+      nscolor uniformColor;
+      PRBool isUniform = item->IsUniform(mBuilder, &uniformColor);
+      PRBool isOpaque = item->IsOpaque(mBuilder);
+      nsIntRect opaqueRect;
+      if (isOpaque) {
+        opaqueRect = item->GetBounds(mBuilder).ToNearestPixels(appUnitsPerDevPixel);
+      }
       nsRefPtr<ThebesLayer> thebesLayer =
-        FindThebesLayerFor(item, itemVisibleRect, itemDrawRect,
-                           activeScrolledRoot);
+        FindThebesLayerFor(itemVisibleRect, itemDrawRect, activeScrolledRoot,
+                           isOpaque ? &opaqueRect : nsnull,
+                           isUniform ? &uniformColor : nsnull);
 
       InvalidateForLayerChange(item, thebesLayer);
 
       mBuilder->LayerBuilder()->
         AddThebesDisplayItem(thebesLayer, item, aClipRect, mContainerFrame,
                              layerState, tempLayerManager);
     }
   }
@@ -1225,46 +1109,25 @@ FrameLayerBuilder::AddLayerDisplayItem(L
 
   nsIFrame* f = aItem->GetUnderlyingFrame();
   DisplayItemDataEntry* entry = mNewDisplayItemData.PutEntry(f);
   if (entry) {
     entry->mData.AppendElement(DisplayItemData(aLayer, aItem->GetPerFrameKey()));
   }
 }
 
-nscolor
-FrameLayerBuilder::FindOpaqueColorCovering(nsDisplayListBuilder* aBuilder,
-                                           ThebesLayer* aLayer,
-                                           const nsRect& aRect)
-{
-  ThebesLayerItemsEntry* entry = mThebesLayerItems.GetEntry(aLayer);
-  NS_ASSERTION(entry, "Must know about this layer!");
-  for (PRInt32 i = entry->mItems.Length() - 1; i >= 0; --i) {
-    nsDisplayItem* item = entry->mItems[i].mItem;
-    const nsRect& visible = item->GetVisibleRect();
-    if (!visible.Intersects(aRect))
-      continue;
-
-    nscolor color;
-    if (visible.Contains(aRect) && item->IsUniform(aBuilder, &color) &&
-        NS_GET_A(color) == 255)
-      return color;
-    break;
-  }
-  return NS_RGBA(0,0,0,0);
-}
-
 void
 ContainerState::CollectOldLayers()
 {
   for (Layer* layer = mContainerLayer->GetFirstChild(); layer;
        layer = layer->GetNextSibling()) {
-    if (layer->HasUserData(&gColorLayerUserData)) {
+    void* data = layer->GetUserData();
+    if (data == &gColorLayerUserData) {
       mRecycledColorLayers.AppendElement(static_cast<ColorLayer*>(layer));
-    } else if (layer->HasUserData(&gThebesDisplayItemLayerUserData)) {
+    } else if (data == &gThebesDisplayItemLayerUserData) {
       NS_ASSERTION(layer->AsThebesLayer(), "Wrong layer type");
       mRecycledThebesLayers.AppendElement(static_cast<ThebesLayer*>(layer));
     }
   }
 }
 
 void
 ContainerState::Finish()
@@ -1335,17 +1198,17 @@ FrameLayerBuilder::BuildContainerLayerFo
                aContainerItem->GetUnderlyingFrame() == aContainerFrame,
                "Container display item must match given frame");
 
   nsRefPtr<ContainerLayer> containerLayer;
   if (aManager == mRetainingManager) {
     Layer* oldLayer = GetOldLayerFor(aContainerFrame, containerDisplayItemKey);
     if (oldLayer) {
       NS_ASSERTION(oldLayer->Manager() == aManager, "Wrong manager");
-      if (oldLayer->HasUserData(&gThebesDisplayItemLayerUserData)) {
+      if (oldLayer->GetUserData() == &gThebesDisplayItemLayerUserData) {
         // The old layer for this item is actually our ThebesLayer
         // because we rendered its layer into that ThebesLayer. So we
         // don't actually have a retained container layer.
       } else {
         NS_ASSERTION(oldLayer->GetType() == Layer::TYPE_CONTAINER,
                      "Wrong layer type");
         containerLayer = static_cast<ContainerLayer*>(oldLayer);
         // Clear clip rect; the caller will set it if necessary.
@@ -1391,35 +1254,34 @@ FrameLayerBuilder::BuildContainerLayerFo
       state.SetInvalidateAllThebesContent();
     }
     SetHasContainerLayer(aContainerFrame);
   }
 
   state.ProcessDisplayItems(aChildren, nsnull);
   state.Finish();
 
-  PRUint32 flags = aChildren.IsOpaque() ? Layer::CONTENT_OPAQUE : 0;
-  containerLayer->SetContentFlags(flags);
+  containerLayer->SetIsOpaqueContent(aChildren.IsOpaque());
   return containerLayer.forget();
 }
 
 Layer*
 FrameLayerBuilder::GetLeafLayerFor(nsDisplayListBuilder* aBuilder,
                                    LayerManager* aManager,
                                    nsDisplayItem* aItem)
 {
   if (aManager != mRetainingManager)
     return nsnull;
 
   nsIFrame* f = aItem->GetUnderlyingFrame();
   NS_ASSERTION(f, "Can only call GetLeafLayerFor on items that have a frame");
   Layer* layer = GetOldLayerFor(f, aItem->GetPerFrameKey());
   if (!layer)
     return nsnull;
-  if (layer->HasUserData(&gThebesDisplayItemLayerUserData)) {
+  if (layer->GetUserData() == &gThebesDisplayItemLayerUserData) {
     // This layer was created to render Thebes-rendered content for this
     // display item. The display item should not use it for its own
     // layer rendering.
     return nsnull;
   }
   // Clear clip rect; the caller is responsible for setting it.
   layer->SetClipRect(nsnull);
   return layer;
@@ -1485,27 +1347,27 @@ FrameLayerBuilder::InvalidateThebesLayer
 {
   InternalInvalidateThebesLayersInSubtree(aFrame);
 }
 
 /* static */ void
 FrameLayerBuilder::InvalidateAllThebesLayerContents(LayerManager* aManager)
 {
   LayerManagerData* data = static_cast<LayerManagerData*>
-    (aManager->GetUserData(&gLayerManagerUserData));
+    (aManager->GetUserData());
   if (data) {
     data->mInvalidateAllThebesContent = PR_TRUE;
   }
 }
 
 /* static */ void
 FrameLayerBuilder::InvalidateAllLayers(LayerManager* aManager)
 {
   LayerManagerData* data = static_cast<LayerManagerData*>
-    (aManager->GetUserData(&gLayerManagerUserData));
+    (aManager->GetUserData());
   if (data) {
     data->mInvalidateAllLayers = PR_TRUE;
   }
 }
 
 /* static */
 PRBool
 FrameLayerBuilder::HasDedicatedLayer(nsIFrame* aFrame, PRUint32 aDisplayItemKey)
@@ -1513,19 +1375,19 @@ FrameLayerBuilder::HasDedicatedLayer(nsI
   void* propValue = aFrame->Properties().Get(DisplayItemDataProperty());
   if (!propValue)
     return PR_FALSE;
 
   nsTArray<DisplayItemData>* array =
     (reinterpret_cast<nsTArray<DisplayItemData>*>(&propValue));
   for (PRUint32 i = 0; i < array->Length(); ++i) {
     if (array->ElementAt(i).mDisplayItemKey == aDisplayItemKey) {
-      Layer* layer = array->ElementAt(i).mLayer;
-      if (!layer->HasUserData(&gColorLayerUserData) &&
-          !layer->HasUserData(&gThebesDisplayItemLayerUserData))
+      void* layerUserData = array->ElementAt(i).mLayer->GetUserData();
+      if (layerUserData != &gColorLayerUserData &&
+          layerUserData != &gThebesDisplayItemLayerUserData)
         return PR_TRUE;
     }
   }
   return PR_FALSE;
 }
 
 /* static */ void
 FrameLayerBuilder::DrawThebesLayer(ThebesLayer* aLayer,
@@ -1544,25 +1406,16 @@ FrameLayerBuilder::DrawThebesLayer(Thebe
     NS_ASSERTION(entry, "We shouldn't be drawing into a layer with no items!");
     items.SwapElements(entry->mItems);
     containerLayerFrame = entry->mContainerLayerFrame;
     // Later after this point, due to calls to DidEndTransaction
     // for temporary layer managers, mThebesLayerItems can change,
     // so 'entry' could become invalid.
   }
 
-  ThebesDisplayItemLayerUserData* userData =
-    static_cast<ThebesDisplayItemLayerUserData*>
-      (aLayer->GetUserData(&gThebesDisplayItemLayerUserData));
-  NS_ASSERTION(userData, "where did our user data go?");
-  if (NS_GET_A(userData->mForcedBackgroundColor) > 0) {
-    aContext->SetColor(gfxRGBA(userData->mForcedBackgroundColor));
-    aContext->Paint();
-  }
-
   gfxMatrix transform;
   if (!aLayer->GetTransform().Is2D(&transform)) {
     NS_ERROR("non-2D transform in our Thebes layer!");
     return;
   }
   NS_ASSERTION(!transform.HasNonIntegerTranslation(),
                "Matrix not just an integer translation?");
   // make the origin of the context coincide with the origin of the
--- a/layout/base/FrameLayerBuilder.h
+++ b/layout/base/FrameLayerBuilder.h
@@ -238,36 +238,16 @@ public:
    * Given a frame and a display item key that uniquely identifies a
    * display item for the frame, find the layer that was last used to
    * render that display item. Returns null if there is no such layer.
    * This could be a dedicated layer for the display item, or a ThebesLayer
    * that renders many display items.
    */
   Layer* GetOldLayerFor(nsIFrame* aFrame, PRUint32 aDisplayItemKey);
 
-  /**
-   * A useful hashtable iteration function that removes the
-   * DisplayItemData property for the frame, clears its
-   * NS_FRAME_HAS_CONTAINER_LAYER bit and returns PL_DHASH_REMOVE.
-   * aClosure is ignored.
-   */
-  static PLDHashOperator RemoveDisplayItemDataForFrame(nsPtrHashKey<nsIFrame>* aEntry,
-                                                       void* aClosure)
-  {
-    return UpdateDisplayItemDataForFrame(aEntry, nsnull);
-  }
-
-  /**
-   * Try to determine whether the ThebesLayer aLayer paints an opaque
-   * single color everywhere it's visible in aRect.
-   * If successful, return that color, otherwise return NS_RGBA(0,0,0,0).
-   */
-  nscolor FindOpaqueColorCovering(nsDisplayListBuilder* aBuilder,
-                                  ThebesLayer* aLayer, const nsRect& aRect);
-
 protected:
   /**
    * We store an array of these for each frame that is associated with
    * one or more retained layers. Each DisplayItemData records the layer
    * used to render one of the frame's display items.
    */
   class DisplayItemData {
   public:
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -1246,19 +1246,19 @@ IsSmoothScrollingEnabled()
       return enabled;
     }
   }
   return PR_FALSE;
 }
 
 class ScrollFrameActivityTracker : public nsExpirationTracker<nsGfxScrollFrameInner,4> {
 public:
-  // Wait for 3-4s between scrolls before we remove our layers.
-  // That's 4 generations of 1s each.
-  enum { TIMEOUT_MS = 1000 };
+  // Wait for 75-100ms between scrolls before we switch the appearance back to
+  // subpixel AA. That's 4 generations of 25ms each.
+  enum { TIMEOUT_MS = 25 };
   ScrollFrameActivityTracker()
     : nsExpirationTracker<nsGfxScrollFrameInner,4>(TIMEOUT_MS) {}
   ~ScrollFrameActivityTracker() {
     AgeAllGenerations();
   }
 
   virtual void NotifyExpired(nsGfxScrollFrameInner *aObject) {
     RemoveObject(aObject);
--- a/layout/reftests/bidi/logicalmarquee.html
+++ b/layout/reftests/bidi/logicalmarquee.html
@@ -1,11 +1,11 @@
 <!DOCTYPE HTML>
 <html>
   <head>
     <meta http-equiv="Content-type" content="text/html; charset=iso-8859-8-i">
     <title>Marquee in Logical Hebrew</title>
   </head>
 
   <body>
-    <marquee scrollamount="0" behavior="alternate" direction="right">&#x05E2;&#x05D3; &#x05E9;&#x05D9;&#x05E4;&#x05D5;&#x05D7; &#x05D4;&#x05D9;&#x05D5;&#x05DD; &#x05D5;&#x05E0;&#x05E1;&#x05D5; &#x05D4;&#x05E6;&#x05DC;&#x05D9;&#x05DC;&#x05D9;&#x05DD;</marquee>
+    <marquee scrollamount="0" behavior="alternate" direction="right" style="opacity:0.9">&#x05E2;&#x05D3; &#x05E9;&#x05D9;&#x05E4;&#x05D5;&#x05D7; &#x05D4;&#x05D9;&#x05D5;&#x05DD; &#x05D5;&#x05E0;&#x05E1;&#x05D5; &#x05D4;&#x05E6;&#x05DC;&#x05D9;&#x05DC;&#x05D9;&#x05DD;</marquee>
  </body>
 </html>
--- a/layout/reftests/bidi/marquee-ref.html
+++ b/layout/reftests/bidi/marquee-ref.html
@@ -1,11 +1,11 @@
 <!DOCTYPE HTML>
 <html>
   <head>
     <meta http-equiv="Content-type" content="text/html; charset=iso-8859-8-i">
     <title>Marquee in Logical Hebrew</title>
   </head>
 
   <body>
-    <div dir="rtl" align="left">&#x05E2;&#x05D3; &#x05E9;&#x05D9;&#x05E4;&#x05D5;&#x05D7; &#x05D4;&#x05D9;&#x05D5;&#x05DD; &#x05D5;&#x05E0;&#x05E1;&#x05D5; &#x05D4;&#x05E6;&#x05DC;&#x05D9;&#x05DC;&#x05D9;&#x05DD;</div>
+    <div dir="rtl" align="left" style="opacity:0.9">&#x05E2;&#x05D3; &#x05E9;&#x05D9;&#x05E4;&#x05D5;&#x05D7; &#x05D4;&#x05D9;&#x05D5;&#x05DD; &#x05D5;&#x05E0;&#x05E1;&#x05D5; &#x05D4;&#x05E6;&#x05DC;&#x05D9;&#x05DC;&#x05D9;&#x05DD;</div>
  </body>
 </html>
--- a/layout/reftests/bidi/visualmarquee.html
+++ b/layout/reftests/bidi/visualmarquee.html
@@ -1,11 +1,11 @@
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 <html>
   <head>
     <meta http-equiv="Content-type" content="text/html; charset=iso-8859-8">
     <title>Marquee in Visual Hebrew</title>
   </head>
 
   <body>
-    <marquee scrollamount="0" behavior="alternate" direction="right">&#x05DD;&#x05D9;&#x05DC;&#x05D9;&#x05DC;&#x05E6;&#x05D4; &#x05D5;&#x05E1;&#x05E0;&#x05D5; &#x05DD;&#x05D5;&#x05D9;&#x05D4; &#x05D7;&#x05D5;&#x05E4;&#x05D9;&#x05E9; &#x05D3;&#x05E2;</marquee>
+    <marquee scrollamount="0" behavior="alternate" direction="right" style="opacity:0.9">&#x05DD;&#x05D9;&#x05DC;&#x05D9;&#x05DC;&#x05E6;&#x05D4; &#x05D5;&#x05E1;&#x05E0;&#x05D5; &#x05DD;&#x05D5;&#x05D9;&#x05D4; &#x05D7;&#x05D5;&#x05E4;&#x05D9;&#x05E9; &#x05D3;&#x05E2;</marquee>
  </body>
 </html>
--- a/layout/reftests/marquee/413027-4-ref.html
+++ b/layout/reftests/marquee/413027-4-ref.html
@@ -1,10 +1,10 @@
 <html><head>
 <title>Testcase for bug 413027 - Marquee height is sized too small, clipping text vertically</title>
 </head>
 <body>
 
 <div style="background-color: lime; width: 600px; float:left;">
-  <div style="margin: 100px 0px; padding-left: 2px;">text</div>
+  <div style="margin: 100px 0px; padding-left: 2px; opacity:0.9;">text</div>
 </div>
       
 </body></html>
--- a/layout/reftests/marquee/413027-4.html
+++ b/layout/reftests/marquee/413027-4.html
@@ -3,13 +3,13 @@
 </head>
 <body>
 
 <marquee scrollamount="0" behavior="alternate" direction="right" style="background-color: lime; width: 600px;">
 <div>
 <!-- padding-left used to avoid risk of an antialiasing pixel that may
      project to the left of the origin, causing a spurious test failure
      (see bugs 476927, 475968) -->
-  <div style="margin: 100px 0px; padding-left: 2px;">text</div>
+  <div style="margin: 100px 0px; padding-left: 2px; opacity:0.9;">text</div>
 </div>
 </marquee>
       
 </body></html>
deleted file mode 100644
--- a/layout/reftests/scrolling/fixed-text-1.html
+++ /dev/null
@@ -1,7 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<body style="height:2000px; overflow:hidden; background:url(repeatable-diagonal-gradient.png) fixed;">
-<script src="scrolling.js"></script>
-<p>Hello Kitty
-</body>
-</html>
--- a/layout/reftests/scrolling/reftest.list
+++ b/layout/reftests/scrolling/reftest.list
@@ -1,7 +1,5 @@
 HTTP == fixed-1.html fixed-1.html?ref
-HTTP == fixed-text-1.html fixed-text-1.html?ref
 HTTP == opacity-mixed-scrolling-1.html opacity-mixed-scrolling-1.html?ref
 HTTP == simple-1.html simple-1.html?ref
-HTTP == text-1.html text-1.html?ref
 == uncovering-1.html uncovering-1-ref.html
 == uncovering-2.html uncovering-2-ref.html
deleted file mode 100644
--- a/layout/reftests/scrolling/text-1.html
+++ /dev/null
@@ -1,10 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<body>
-<script src="scrolling.js"></script>
-<div class="scrollTop" style="height:100px; overflow:auto;">
-  <div style="margin-top:30px;">Hello Kitty</div>
-  <div style="height:400px;"></div>
-</div>
-</body>
-</html>