Bug 579276. Part 7: Don't retain transparent layers that would hurt text rendering. r=cjones
authorRobert O'Callahan <robert@ocallahan.org>
Thu, 02 Sep 2010 21:18:41 +1200
changeset 51881 671d64fcf6ac2f3a910e21d3d6f707ff9ac17bbf
parent 51880 60c348050159e364b68cf162820c7e3701655563
child 51882 e1ea8cd9f88372f5f4138a58bc70ebd7dfdb912c
push idunknown
push userunknown
push dateunknown
reviewerscjones
bugs579276
milestone2.0b6pre
Bug 579276. Part 7: Don't retain transparent layers that would hurt text rendering. r=cjones
gfx/layers/basic/BasicLayers.cpp
--- a/gfx/layers/basic/BasicLayers.cpp
+++ b/gfx/layers/basic/BasicLayers.cpp
@@ -362,53 +362,72 @@ 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();
 
-  if (!BasicManager()->IsRetained()) {
+  PRBool canUseOpaqueSurface = CanUseOpaqueSurface();
+  if (!BasicManager()->IsRetained() ||
+      (aOpacity == 1.0 && !canUseOpaqueSurface &&
+       !ShouldRetainTransparentSurface(mContentFlags, targetSurface))) {
+    mValidRegion.SetEmpty();
+    mBuffer.Clear();
+
     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 =
-      isOpaqueContent ? gfxASurface::CONTENT_COLOR :
-                        gfxASurface::CONTENT_COLOR_ALPHA;
+      opaqueBuffer ? 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)
@@ -420,17 +439,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, isOpaqueContent, target, aOpacity);
+  mBuffer.DrawTo(this, canUseOpaqueSurface, target, aOpacity);
 }
 
 void
 BasicThebesLayerBuffer::DrawTo(ThebesLayer* aLayer,
                                PRBool aIsOpaqueContent,
                                gfxContext* aTarget,
                                float aOpacity)
 {