b=573626 support force-24bpp in gfxXlibSurface::CreateSimilar r=vlad
authorKarl Tomlinson <karlt+@karlt.net>
Fri, 16 Jul 2010 09:08:09 +1200
changeset 47760 0bf4062002381b808f0f51fc8912580049e2034d
parent 47759 51dc121aa5258a9d1f27586020490bdab8937a4c
child 47761 4abcf73fe93a63591a687729a4b78721dc118394
push idunknown
push userunknown
push dateunknown
reviewersvlad
bugs573626
milestone2.0b2pre
b=573626 support force-24bpp in gfxXlibSurface::CreateSimilar r=vlad
gfx/thebes/gfxXlibSurface.cpp
gfx/thebes/gfxXlibSurface.h
--- a/gfx/thebes/gfxXlibSurface.cpp
+++ b/gfx/thebes/gfxXlibSurface.cpp
@@ -37,17 +37,20 @@
  * ***** END LICENSE BLOCK ***** */
 
 #include "gfxXlibSurface.h"
 
 #include "cairo.h"
 #include "cairo-xlib.h"
 #include "cairo-xlib-xrender.h"
 #include <X11/Xlibint.h>	/* For XESetCloseDisplay */
+
 #include "nsTArray.h"
+#include "nsServiceManagerUtils.h"
+#include "nsIPrefService.h"
 
 // Although the dimension parameters in the xCreatePixmapReq wire protocol are
 // 16-bit unsigned integers, the server's CreatePixmap returns BadAlloc if
 // either dimension cannot be represented by a 16-bit *signed* integer.
 #define XLIB_IMAGE_SIDE_SIZE_LIMIT 0x7fff
 
 gfxXlibSurface::gfxXlibSurface(Display *dpy, Drawable drawable, Visual *visual)
     : mPixmapTaken(PR_FALSE), mDisplay(dpy), mDrawable(drawable)
@@ -154,16 +157,70 @@ gfxXlibSurface::Create(Screen *screen, X
     result->TakePixmap();
 
     if (result->CairoStatus() != 0)
         return nsnull;
 
     return result.forget();
 }
 
+static PRBool GetForce24bppPref()
+{
+    PRBool val = PR_FALSE; // default
+
+    nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
+    if (!prefs)
+        return val;
+
+    prefs->GetBoolPref("mozilla.widget.force-24bpp", &val);
+    return val;
+}
+
+already_AddRefed<gfxASurface>
+gfxXlibSurface::CreateSimilarSurface(gfxContentType aContent,
+                                     const gfxIntSize& aSize)
+{
+    if (aContent == CONTENT_COLOR) {
+        // If the destination surface does not have an xrender format, then we
+        // won't be able to copy directly from another Xlib surface with a
+        // different format.  Either an xlib surface with the same visual (for
+        // XCopyArea) or an image surface might be sensible options there, but
+        // we just leave the decision to cairo_surface_create_similar.
+        XRenderPictFormat* format =
+            cairo_xlib_surface_get_xrender_format(CairoSurface());
+        if (format) {
+            // cairo_surface_create_similar will use a matching visual if it
+            // can.  However, systems with 16-bit or indexed default visuals
+            // may benefit from rendering with 24-bit formats.  This same code
+            // can also be used for opaque surfaces when not forcing 24-bit,
+            // so as to skip the black initialization that
+            // cairo_surface_create_simiar does.
+            static PRBool force24bpp = GetForce24bppPref();
+
+            if (force24bpp || (format->type == PictTypeDirect
+                               && format->direct.alphaMask != 0)) {
+                format = XRenderFindStandardFormat(mDisplay,
+                                                   PictStandardRGB24);
+            }
+
+            if (format) {
+                Screen* screen = cairo_xlib_surface_get_screen(CairoSurface());
+                nsRefPtr<gfxASurface> result =
+                    gfxXlibSurface::Create(screen, format, aSize, mDrawable);
+            
+                if (result)
+                    return result.forget();
+            }
+        }
+    }
+
+    // Fall back to cairo_surface_create_similar().
+    return gfxASurface::CreateSimilarSurface(aContent, aSize);
+}
+
 void
 gfxXlibSurface::DoSizeQuery()
 {
     // figure out width/height/depth
     Window root_ignore;
     int x_ignore, y_ignore;
     unsigned int bwidth_ignore, width, height, depth;
 
--- a/gfx/thebes/gfxXlibSurface.h
+++ b/gfx/thebes/gfxXlibSurface.h
@@ -69,16 +69,19 @@ public:
     Create(Screen *screen, Visual *visual, const gfxIntSize& size,
            Drawable relatedDrawable = None);
     static already_AddRefed<gfxXlibSurface>
     Create(Screen* screen, XRenderPictFormat *format, const gfxIntSize& size,
            Drawable relatedDrawable = None);
 
     virtual ~gfxXlibSurface();
 
+    virtual already_AddRefed<gfxASurface>
+    CreateSimilarSurface(gfxContentType aType, const gfxIntSize& aSize);
+
     const gfxIntSize& GetSize() { return mSize; }
 
     Display* XDisplay() { return mDisplay; }
     Drawable XDrawable() { return mDrawable; }
 
     static int DepthOfVisual(const Screen* screen, const Visual* visual);
     static XRenderPictFormat *FindRenderFormat(Display *dpy, gfxImageFormat format);