Bug 606910 - RENDER_DIRECT mode for Qt widget (xshmPutImage). r=dougt a=blocking-fennec
authorOleg Romashin <romaxa@gmail.com>
Wed, 27 Oct 2010 07:56:31 +0300
changeset 56628 8fc4f0abe03fe74753c0a2eb51e493da60734f73
parent 56627 dd50da0646a4732c3f862cf5280a072930b40332
child 56629 2ee46939bb9e668514c75059d284ae5205f44c95
push idunknown
push userunknown
push dateunknown
reviewersdougt, blocking-fennec
bugs606910
milestone2.0b8pre
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
Bug 606910 - RENDER_DIRECT mode for Qt widget (xshmPutImage). r=dougt a=blocking-fennec
gfx/thebes/gfxQtPlatform.cpp
gfx/thebes/gfxQtPlatform.h
widget/src/gtk2/nsWindow.cpp
widget/src/qt/Makefile.in
widget/src/qt/mozqwidget.cpp
widget/src/qt/nsWindow.cpp
widget/src/qt/nsWindow.h
widget/src/shared/Makefile.in
widget/src/shared/nsShmImage.cpp
widget/src/shared/nsShmImage.h
--- a/gfx/thebes/gfxQtPlatform.cpp
+++ b/gfx/thebes/gfxQtPlatform.cpp
@@ -76,17 +76,21 @@
 #include FT_FREETYPE_H
 #endif
 
 #include "nsIPrefBranch.h"
 #include "nsIPrefService.h"
 
 // Because the QPainter backend has some problems with glyphs rendering
 // it is better to use image or xlib cairo backends by default
+#if (MOZ_PLATFORM_MAEMO == 6)
 #define DEFAULT_RENDER_MODE RENDER_BUFFERED
+#else
+#define DEFAULT_RENDER_MODE RENDER_DIRECT
+#endif
 
 static QPaintEngine::Type sDefaultQtPaintEngineType = QPaintEngine::X11;
 gfxFontconfigUtils *gfxQtPlatform::sFontconfigUtils = nsnull;
 static cairo_user_data_key_t cairo_qt_pixmap_key;
 static void do_qt_pixmap_unref (void *data)
 {
     QPixmap *pmap = (QPixmap*)data;
     delete pmap;
@@ -141,16 +145,19 @@ gfxQtPlatform::gfxQtPlatform()
 
     switch (ival) {
         case 0:
             mRenderMode = RENDER_QPAINTER;
             break;
         case 1:
             mRenderMode = RENDER_BUFFERED;
             break;
+        case 2:
+            mRenderMode = RENDER_DIRECT;
+            break;
         default:
             mRenderMode = RENDER_QPAINTER;
     }
 
     // Qt doesn't provide a public API to detect the graphicssystem type. We hack
     // around this by checking what type of graphicssystem a test QPixmap uses.
     QPixmap pixmap(1, 1);
     sDefaultQtPaintEngineType = pixmap.paintEngine()->type();
@@ -202,17 +209,17 @@ gfxQtPlatform::CreateOffscreenSurface(co
 
 #ifdef CAIRO_HAS_QT_SURFACE
     if (mRenderMode == RENDER_QPAINTER) {
       newSurface = new gfxQPainterSurface(size, imageFormat);
       return newSurface.forget();
     }
 #endif
 
-    if (mRenderMode == RENDER_BUFFERED &&
+    if ((mRenderMode == RENDER_BUFFERED || mRenderMode == RENDER_DIRECT) &&
         sDefaultQtPaintEngineType != QPaintEngine::X11) {
       newSurface = new gfxImageSurface(size, imageFormat);
       return newSurface.forget();
     }
 
 #ifdef MOZ_X11
     XRenderPictFormat* xrenderFormat =
         gfxXlibSurface::FindRenderFormat(QX11Info().display(), imageFormat);
--- a/gfx/thebes/gfxQtPlatform.h
+++ b/gfx/thebes/gfxQtPlatform.h
@@ -55,16 +55,18 @@ class FontEntry;
 class THEBES_API gfxQtPlatform : public gfxPlatform {
 public:
 
     enum RenderMode {
         /* Use QPainter surfaces */
         RENDER_QPAINTER = 0,
         /* Use offscreen buffer for rendering with image or xlib gfx backend */
         RENDER_BUFFERED,
+        /* Direct rendering to Widget surface */
+        RENDER_DIRECT,
         /* max */
         RENDER_MODE_MAX
     };
 
     gfxQtPlatform();
     virtual ~gfxQtPlatform();
 
     static gfxQtPlatform *GetPlatform() {
--- a/widget/src/gtk2/nsWindow.cpp
+++ b/widget/src/gtk2/nsWindow.cpp
@@ -130,16 +130,18 @@ extern "C" {
 #include "Layers.h"
 #include "LayerManagerOGL.h"
 #include "GLContextProvider.h"
 
 #ifdef MOZ_X11
 #include "gfxXlibSurface.h"
 #endif
 
+#include "nsShmImage.h"
+
 #ifdef MOZ_DFB
 extern "C" {
 #ifdef MOZ_DIRECT_DEBUG
 #define DIRECT_ENABLE_DEBUG
 #endif
 
 #include <direct/debug.h>
 
@@ -281,26 +283,16 @@ static void
 UpdateLastInputEventTime()
 {
   nsCOMPtr<nsIdleService> idleService = do_GetService("@mozilla.org/widget/idleservice;1");
   if (idleService) {
     idleService->ResetIdleTimeOut();
   }
 }
 
-#ifdef MOZ_HAVE_SHMIMAGE
-// If XShm isn't available to our client, we'll try XShm once, fail,
-// set this to false and then never try again.
-static PRBool gShmAvailable = PR_TRUE;
-static PRBool UseShm()
-{
-    return gfxPlatformGtk::UseClientSideRendering() && gShmAvailable;
-}
-#endif
-
 // this is the last window that had a drag event happen on it.
 nsWindow *nsWindow::mLastDragMotionWindow = NULL;
 PRBool nsWindow::sIsDraggingOutOf = PR_FALSE;
 
 // This is the time of the last button press event.  The drag service
 // uses it as the time to start drags.
 guint32   nsWindow::sLastButtonPressTime = 0;
 // Time of the last button release event. We use it to detect when the
@@ -384,169 +376,16 @@ protected:
         pixman_region32_fini(&region);
     }
     // Whether this needs to be released:
     PRBool HaveResource() const { return data != nsnull; }
 
     pixman_region32& get() { return *this; }
 };
 
-
-#ifdef MOZ_HAVE_SHMIMAGE
-
-using mozilla::ipc::SharedMemorySysV;
-
-class nsShmImage {
-    NS_INLINE_DECL_REFCOUNTING(nsShmImage)
-
-public:
-    typedef gfxASurface::gfxImageFormat Format;
-
-    static already_AddRefed<nsShmImage>
-    Create(const gfxIntSize& aSize, Visual* aVisual, unsigned int aDepth);
-
-    ~nsShmImage() {
-        if (mImage) {
-            if (mXAttached) {
-                XShmDetach(gdk_x11_get_default_xdisplay(), &mInfo);
-            }
-            XDestroyImage(mImage);
-        }
-    }
-
-    already_AddRefed<gfxASurface> AsSurface();
-
-    void Put(GdkWindow* aWindow, GdkRectangle* aRects, GdkRectangle* aEnd);
-
-    gfxIntSize Size() const { return mSize; }
-
-private:
-    nsShmImage()
-        : mImage(nsnull)
-        , mXAttached(PR_FALSE)
-    { mInfo.shmid = SharedMemorySysV::NULLHandle(); }
-
-    nsRefPtr<SharedMemorySysV>   mSegment;
-    XImage*                      mImage;
-    XShmSegmentInfo              mInfo;
-    gfxIntSize                   mSize;
-    Format                       mFormat;
-    PRPackedBool                 mXAttached;
-};
-
-already_AddRefed<nsShmImage>
-nsShmImage::Create(const gfxIntSize& aSize,
-                   Visual* aVisual, unsigned int aDepth)
-{
-    Display* dpy = gdk_x11_get_default_xdisplay();
-
-    nsRefPtr<nsShmImage> shm = new nsShmImage();
-    shm->mImage = XShmCreateImage(dpy, aVisual, aDepth,
-                                  ZPixmap, nsnull,
-                                  &(shm->mInfo),
-                                  aSize.width, aSize.height);
-    if (!shm->mImage) {
-        return nsnull;
-    }
-
-    size_t size = shm->mImage->bytes_per_line * shm->mImage->height;
-    shm->mSegment = new SharedMemorySysV();
-    if (!shm->mSegment->Create(size) || !shm->mSegment->Map(size)) {
-        return nsnull;
-    }
-
-    shm->mInfo.shmid = shm->mSegment->GetHandle();
-    shm->mInfo.shmaddr =
-        shm->mImage->data = static_cast<char*>(shm->mSegment->memory());
-    shm->mInfo.readOnly = False;
-
-    gdk_error_trap_push();
-    Status attachOk = XShmAttach(dpy, &shm->mInfo);
-    gint xerror = gdk_error_trap_pop();
-
-    if (!attachOk || xerror) {
-        // Assume XShm isn't available, and don't attempt to use it
-        // again.
-        gShmAvailable = PR_FALSE;
-        return nsnull;
-    }
-
-    shm->mXAttached = PR_TRUE;
-    shm->mSize = aSize;
-    switch (shm->mImage->depth) {
-    case 24:
-        shm->mFormat = gfxASurface::ImageFormatRGB24; break;
-    case 16:
-        shm->mFormat = gfxASurface::ImageFormatRGB16_565; break;
-    default:
-        NS_WARNING("Unsupported XShm Image depth!");
-        gShmAvailable = PR_FALSE;
-        return nsnull;
-    }
-    return shm.forget();
-}
-
-already_AddRefed<gfxASurface>
-nsShmImage::AsSurface()
-{
-    return nsRefPtr<gfxASurface>(
-        new gfxImageSurface(static_cast<unsigned char*>(mSegment->memory()),
-                            mSize,
-                            mImage->bytes_per_line,
-                            mFormat)
-        ).forget();
-}
-
-void
-nsShmImage::Put(GdkWindow* aWindow, GdkRectangle* aRects, GdkRectangle* aEnd)
-{
-    GdkDrawable* gd;
-    gint dx, dy;
-    gdk_window_get_internal_paint_info(aWindow, &gd, &dx, &dy);
-
-    Display* dpy = gdk_x11_get_default_xdisplay();
-    Drawable d = GDK_DRAWABLE_XID(gd);
-
-    GC gc = XCreateGC(dpy, d, 0, nsnull);
-    for (GdkRectangle* r = aRects; r < aEnd; r++) {
-        XShmPutImage(dpy, d, gc, mImage,
-                     r->x, r->y,
-                     r->x - dx, r->y - dy,
-                     r->width, r->height,
-                     False);
-    }
-    XFreeGC(dpy, gc);
-
-    // FIXME/bug 597336: we need to ensure that the shm image isn't
-    // scribbled over before all its pending XShmPutImage()s complete.
-    // However, XSync() is an unnecessarily heavyweight
-    // synchronization mechanism; other options are possible.  If this
-    // XSync is shown to hurt responsiveness, we need to explore the
-    // other options.
-    XSync(dpy, False);
-}
-
-static already_AddRefed<gfxASurface>
-EnsureShmImage(const gfxIntSize& aSize, Visual* aVisual, unsigned int aDepth,
-               nsRefPtr<nsShmImage>& aImage)
-{
-    if (!aImage || aImage->Size() != aSize) {
-        // Because we XSync() after XShmAttach() to trap errors, we
-        // know that the X server has the old image's memory mapped
-        // into its address space, so it's OK to destroy the old image
-        // here even if there are outstanding Puts.  The Detach is
-        // ordered after the Puts.
-        aImage = nsShmImage::Create(aSize, aVisual, aDepth);
-    }
-    return !aImage ? nsnull : aImage->AsSurface();
-}
-
-#endif  // defined(MOZ_X11) && defined(MOZ_HAVE_SHAREDMEMORYSYSV)
-
-
 nsWindow::nsWindow()
 {
     mIsTopLevel       = PR_FALSE;
     mIsDestroyed      = PR_FALSE;
     mNeedsResize      = PR_FALSE;
     mNeedsMove        = PR_FALSE;
     mListenForResizes = PR_FALSE;
     mIsShown          = PR_FALSE;
@@ -2341,17 +2180,17 @@ nsWindow::OnExposeEvent(GtkWidget *aWidg
     BasicLayerManager::BufferMode layerBuffering;
     if (translucent) {
         // The double buffering is done here to extract the shape mask.
         // (The shape mask won't be necessary when a visual with an alpha
         // channel is used on compositing window managers.)
         layerBuffering = BasicLayerManager::BUFFER_NONE;
         ctx->PushGroup(gfxASurface::CONTENT_COLOR_ALPHA);
 #ifdef MOZ_HAVE_SHMIMAGE
-    } else if (UseShm()) {
+    } else if (nsShmImage::UseShm()) {
         // We're using an xshm mapping as a back buffer.
         layerBuffering = BasicLayerManager::BUFFER_NONE;
 #endif // MOZ_HAVE_SHMIMAGE
     } else {
         // Get the layer manager to do double buffering (if necessary).
         layerBuffering = BasicLayerManager::BUFFER_BUFFERED;
     }
 
@@ -2400,17 +2239,17 @@ nsWindow::OnExposeEvent(GtkWidget *aWidg
                     UpdateTranslucentWindowAlphaInternal(nsIntRect(boundsRect.x, boundsRect.y,
                                                                    boundsRect.width, boundsRect.height),
                                                          img->Data(), img->Stride());
                 }
             }
         }
     }
 #  ifdef MOZ_HAVE_SHMIMAGE
-    if (UseShm() && NS_LIKELY(!mIsDestroyed)) {
+    if (nsShmImage::UseShm() && NS_LIKELY(!mIsDestroyed)) {
         mShmImage->Put(mGdkWindow, rects, r_end);
     }
 #  endif  // MOZ_HAVE_SHMIMAGE
 #endif // MOZ_X11
 
     g_free(rects);
 
     nsPaintEvent didPaintEvent(PR_TRUE, NS_DID_PAINT, this);
@@ -6701,23 +6540,24 @@ nsWindow::GetThebesSurface()
     // Owen Taylor says this is the right thing to do!
     width = PR_MIN(32767, width);
     height = PR_MIN(32767, height);
     gfxIntSize size(width, height);
     Visual* visual = GDK_VISUAL_XVISUAL(gdk_drawable_get_visual(d));
 
 #  ifdef MOZ_HAVE_SHMIMAGE
     PRBool usingShm = PR_FALSE;
-    if (UseShm()) {
+    if (nsShmImage::UseShm()) {
         // EnsureShmImage() is a dangerous interface, but we guarantee
         // that the thebes surface and the shmimage have the same
         // lifetime
-        mThebesSurface = EnsureShmImage(size,
-                                        visual, gdk_drawable_get_depth(d),
-                                        mShmImage);
+        mThebesSurface =
+            nsShmImage::EnsureShmImage(size,
+                                       visual, gdk_drawable_get_depth(d),
+                                       mShmImage);
         usingShm = mThebesSurface != nsnull;
     }
     if (!usingShm)
 #  endif  // MOZ_HAVE_SHMIMAGE
 
     mThebesSurface = new gfxXlibSurface
         (GDK_WINDOW_XDISPLAY(d),
          GDK_WINDOW_XWINDOW(d),
--- a/widget/src/qt/Makefile.in
+++ b/widget/src/qt/Makefile.in
@@ -98,16 +98,18 @@ EXTRA_DSO_LDOPTS = \
 
 EXTRA_DSO_LDOPTS += -L$(DIST)/lib $(MOZ_XLIB_LDFLAGS) $(XLIBS)
 
 # If not primary toolkit, install in secondary path
 ifneq (qt,$(MOZ_WIDGET_TOOLKIT))
 INACTIVE_COMPONENT = 1
 endif
 
+include $(topsrcdir)/config/config.mk
+include $(topsrcdir)/ipc/chromium/chromium-config.mk
 include $(topsrcdir)/config/rules.mk
 
 CXXFLAGS	+= $(MOZ_QT_CFLAGS) $(GLIB_CFLAGS) $(MOZ_CAIRO_CFLAGS)
 CFLAGS		+= $(MOZ_QT_CFLAGS) $(GLIB_CFLAGS) $(MOZ_CAIRO_CFLAGS)
 
 DEFINES		+= -D_IMPL_NS_WIDGET
 #DEFINES		+= -DDEBUG_WIDGETS
 
@@ -126,9 +128,10 @@ endif
 endif
 
 LOCAL_INCLUDES	+= \
 		   -I$(topsrcdir)/widget/src/xpwidgets \
 		   -I$(srcdir) \
 		   $(NULL)
 ifdef MOZ_X11
 INCLUDES   	+= -I$(srcdir)/../shared/x11
+INCLUDES   	+= -I$(srcdir)/../shared
 endif
--- a/widget/src/qt/mozqwidget.cpp
+++ b/widget/src/qt/mozqwidget.cpp
@@ -87,17 +87,17 @@ MozQWidget::MozQWidget(nsWindow* aReceiv
 MozQWidget::~MozQWidget()
 {
     if (mReceiver)
         mReceiver->QWidgetDestroyed();
 }
 
 void MozQWidget::paint(QPainter* aPainter, const QStyleOptionGraphicsItem* aOption, QWidget* aWidget /*= 0*/)
 {
-    mReceiver->DoPaint(aPainter, aOption);
+    mReceiver->DoPaint(aPainter, aOption, aWidget);
 }
 
 void MozQWidget::activate()
 {
     // ensure that the keyboard is hidden when we activate the window
     hideVKB();
     mReceiver->DispatchActivateEventOnTopLevelWindow();
 }
--- a/widget/src/qt/nsWindow.cpp
+++ b/widget/src/qt/nsWindow.cpp
@@ -123,21 +123,32 @@ static const float GESTURES_BLOCK_MOUSE_
 #include "keysym2ucs.h"
 #endif //MOZ_X11
 
 #include <QtOpenGL/QGLWidget>
 #define GLdouble_defined 1
 #include "Layers.h"
 #include "LayerManagerOGL.h"
 
+#include "nsShmImage.h"
+extern "C" {
+#include "pixman.h"
+}
+
+using namespace mozilla;
+
 // imported in nsWidgetFactory.cpp
 PRBool gDisableNativeTheme = PR_FALSE;
 
 // Cached offscreen surface
 static nsRefPtr<gfxASurface> gBufferSurface;
+#ifdef MOZ_HAVE_SHMIMAGE
+// If we're using xshm rendering, mThebesSurface wraps gShmImage
+nsRefPtr<nsShmImage> gShmImage;
+#endif
 
 static int gBufferPixmapUsageCount = 0;
 static gfxIntSize gBufferMaxSize(0, 0);
 
 /* For PrepareNativeWidget */
 static NS_DEFINE_IID(kDeviceContextCID, NS_DEVICE_CONTEXT_CID);
 
 // initialization static functions 
@@ -263,17 +274,17 @@ static inline QImage::Format
     case gfxASurface::ImageFormatRGB16_565:
         return QImage::Format_RGB16;
     default:
         return QImage::Format_Invalid;
     }
 }
 
 static bool
-UpdateOffScreenBuffers(int aDepth, QSize aSize)
+UpdateOffScreenBuffers(int aDepth, QSize aSize, QWidget* aWidget = nsnull)
 {
     gfxIntSize size(aSize.width(), aSize.height());
     if (gBufferSurface) {
         if (gBufferMaxSize.width < size.width ||
             gBufferMaxSize.height < size.height) {
             gBufferSurface = nsnull;
         } else
             return true;
@@ -285,18 +296,32 @@ UpdateOffScreenBuffers(int aDepth, QSize
     // Check if system depth has related gfxImage format
     gfxASurface::gfxImageFormat format =
         _depth_to_gfximage_format(aDepth);
 
     // Use fallback RGB24 format, Qt will do conversion for us
     if (format == gfxASurface::ImageFormatUnknown)
         format = gfxASurface::ImageFormatRGB24;
 
+#ifdef MOZ_HAVE_SHMIMAGE
+    if (aWidget) {
+        if (gfxPlatform::GetPlatform()->ScreenReferenceSurface()->GetType() ==
+            gfxASurface::SurfaceTypeImage) {
+            gShmImage = nsShmImage::Create(gBufferMaxSize,
+                                           (Visual*)aWidget->x11Info().visual(),
+                                           aDepth);
+            gBufferSurface = gShmImage->AsSurface();
+            return true;
+        }
+    }
+#endif
+
     gBufferSurface = gfxPlatform::GetPlatform()->
         CreateOffscreenSurface(gBufferMaxSize, gfxASurface::ContentFromFormat(format));
+
     return true;
 }
 
 nsWindow::~nsWindow()
 {
     LOG(("%s [%p]\n", __PRETTY_FUNCTION__, (void *)this));
 
     Destroy();
@@ -338,16 +363,19 @@ nsWindow::Destroy(void)
 
     LOG(("nsWindow::Destroy [%p]\n", (void *)this));
     mIsDestroyed = PR_TRUE;
 
     if (gBufferPixmapUsageCount &&
         --gBufferPixmapUsageCount == 0) {
 
         gBufferSurface = nsnull;
+#ifdef MOZ_HAVE_SHMIMAGE
+        gShmImage = nsnull;
+#endif
     }
 
     nsCOMPtr<nsIWidget> rollupWidget = do_QueryReferent(gRollupWindow);
     if (static_cast<nsIWidget *>(this) == rollupWidget.get()) {
         if (gRollupListener)
             gRollupListener->Rollup(nsnull, nsnull);
         gRollupWindow = nsnull;
         gRollupListener = nsnull;
@@ -936,18 +964,33 @@ is_mouse_in_window (MozQWidget* aWindow,
 
 NS_IMETHODIMP
 nsWindow::GetAttention(PRInt32 aCycleCount)
 {
     LOG(("nsWindow::GetAttention [%p]\n", (void *)this));
     return NS_ERROR_NOT_IMPLEMENTED;
 }
 
+#ifdef MOZ_X11
+static already_AddRefed<gfxASurface>
+GetSurfaceForQWidget(QWidget* aDrawable)
+{
+    gfxASurface* result =
+        new gfxXlibSurface(aDrawable->x11Info().display(),
+                           aDrawable->handle(),
+                           (Visual*)aDrawable->x11Info().visual(),
+                           gfxIntSize(aDrawable->size().width(),
+                           aDrawable->size().height()));
+    NS_IF_ADDREF(result);
+    return result;
+}
+#endif
+
 nsEventStatus
-nsWindow::DoPaint(QPainter* aPainter, const QStyleOptionGraphicsItem* aOption)
+nsWindow::DoPaint(QPainter* aPainter, const QStyleOptionGraphicsItem* aOption, QWidget* aWidget)
 {
     if (mIsDestroyed) {
         LOG(("Expose event on destroyed window [%p] window %p\n",
              (void *)this, mWidget));
         return nsEventStatus_eIgnore;
     }
 
     if (!mWidget)
@@ -988,35 +1031,53 @@ nsWindow::DoPaint(QPainter* aPainter, co
             return nsEventStatus_eIgnore;
 
         targetSurface = gBufferSurface;
 
 #ifdef CAIRO_HAS_QT_SURFACE
     } else if (renderMode == gfxQtPlatform::RENDER_QPAINTER) {
         targetSurface = new gfxQPainterSurface(aPainter);
 #endif
+    } else if (renderMode == gfxQtPlatform::RENDER_DIRECT) {
+        if (!UpdateOffScreenBuffers(depth, aWidget->size(), aWidget)) {
+            return nsEventStatus_eIgnore;
+        }
+        targetSurface = gBufferSurface;
     }
 
     if (NS_UNLIKELY(!targetSurface))
         return nsEventStatus_eIgnore;
 
     nsRefPtr<gfxContext> ctx = new gfxContext(targetSurface);
 
     // We will paint to 0, 0 position in offscrenn buffer
-    if (renderMode == gfxQtPlatform::RENDER_BUFFERED)
+    if (renderMode == gfxQtPlatform::RENDER_BUFFERED) {
         ctx->Translate(gfxPoint(-r.x(), -r.y()));
+    }
+    else if (renderMode == gfxQtPlatform::RENDER_DIRECT) {
+        // This is needed for rotate transformation on Meego
+        // This will work very slow if pixman does not handle rotation very well
+        gfxMatrix matr(aPainter->transform().m11(),
+                       aPainter->transform().m12(),
+                       aPainter->transform().m21(),
+                       aPainter->transform().m22(),
+                       aPainter->transform().dx(),
+                       aPainter->transform().dy());
+        ctx->SetMatrix(matr);
+        NS_ASSERTION(PIXMAN_VERSION < PIXMAN_VERSION_ENCODE(0, 21, 2) && aPainter->transform().isRotating(), "Old pixman and rotate transform, it is going to be slow");
+    }
 
     nsPaintEvent event(PR_TRUE, NS_PAINT, this);
-    event.refPoint.x = r.x();
-    event.refPoint.y = r.y();
+    event.refPoint.x = rect.x;
+    event.refPoint.y = rect.y;
     event.region = nsIntRegion(rect);
     {
-      AutoLayerManagerSetup
-          setupLayerManager(this, ctx, BasicLayerManager::BUFFER_NONE);
-      status = DispatchEvent(&event);
+        AutoLayerManagerSetup
+            setupLayerManager(this, ctx, BasicLayerManager::BUFFER_NONE);
+        status = DispatchEvent(&event);
     }
 
     // DispatchEvent can Destroy us (bug 378273), avoid doing any paint
     // operations below if that happened - it will lead to XError and exit().
     if (NS_UNLIKELY(mIsDestroyed))
         return status;
 
     if (status == nsEventStatus_eIgnore)
@@ -1042,16 +1103,40 @@ nsWindow::DoPaint(QPainter* aPainter, co
             QImage img(imgs->Data(),
                        imgs->Width(),
                        imgs->Height(),
                        imgs->Stride(),
                        _gfximage_to_qformat(imgs->Format()));
             aPainter->drawImage(QPoint(rect.x, rect.y), img,
                                 QRect(0, 0, rect.width, rect.height));
         }
+    } else if (renderMode == gfxQtPlatform::RENDER_DIRECT) {
+        QRect trans = aPainter->transform().mapRect(r).toRect();
+        if (gBufferSurface->GetType() == gfxASurface::SurfaceTypeXlib) {
+            nsRefPtr<gfxASurface> widgetSurface = GetSurfaceForQWidget(aWidget);
+            nsRefPtr<gfxContext> ctx = new gfxContext(widgetSurface);
+            ctx->SetSource(gBufferSurface);
+            ctx->Rectangle(gfxRect(trans.x(), trans.y(), trans.width(), trans.height()), PR_TRUE);
+            ctx->Clip();
+            ctx->Fill();
+        } else if (gBufferSurface->GetType() == gfxASurface::SurfaceTypeImage) {
+#ifdef MOZ_HAVE_SHMIMAGE
+            if (gShmImage) {
+                gShmImage->Put(aWidget, trans);
+            } else
+#endif
+            if (gBufferSurface) {
+                nsRefPtr<gfxASurface> widgetSurface = GetSurfaceForQWidget(aWidget);
+                nsRefPtr<gfxContext> ctx = new gfxContext(widgetSurface);
+                ctx->SetSource(gBufferSurface);
+                ctx->Rectangle(gfxRect(trans.x(), trans.y(), trans.width(), trans.height()), PR_TRUE);
+                ctx->Clip();
+                ctx->Fill();
+            }
+        }
     }
 
     ctx = nsnull;
     targetSurface = nsnull;
 
     // check the return value!
     return status;
 }
@@ -2470,16 +2555,21 @@ nsWindow::createQWidget(MozQWidget *pare
         if (!newView) {
             delete widget;
             return nsnull;
         }
         if (!IsAcceleratedQView(newView) && GetShouldAccelerate()) {
             newView->setViewport(new QGLWidget());
         }
 
+        if (gfxQtPlatform::GetPlatform()->GetRenderMode() == gfxQtPlatform::RENDER_DIRECT) {
+            // Disable double buffer and system background rendering
+            newView->viewport()->setAttribute(Qt::WA_PaintOnScreen, true);
+            newView->viewport()->setAttribute(Qt::WA_NoSystemBackground, true);
+        }
         // Enable gestures:
 #if (QT_VERSION >= QT_VERSION_CHECK(4, 6, 0))
         newView->viewport()->grabGesture(Qt::PinchGesture);
         newView->viewport()->grabGesture(gSwipeGestureId);
 #endif
         newView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
         newView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
 
@@ -2523,18 +2613,18 @@ gfxASurface*
 nsWindow::GetThebesSurface()
 {
     /* This is really a dummy surface; this is only used when doing reflow, because
      * we need a RenderingContext to measure text against.
      */
     if (mThebesSurface)
         return mThebesSurface;
 
+#ifdef CAIRO_HAS_QT_SURFACE
     gfxQtPlatform::RenderMode renderMode = gfxQtPlatform::GetPlatform()->GetRenderMode();
-#ifdef CAIRO_HAS_QT_SURFACE
     if (renderMode == gfxQtPlatform::RENDER_QPAINTER) {
         mThebesSurface = new gfxQPainterSurface(gfxIntSize(1, 1), gfxASurface::CONTENT_COLOR);
     }
 #endif
     if (!mThebesSurface) {
         gfxASurface::gfxImageFormat imageFormat = gfxASurface::ImageFormatRGB24;
         mThebesSurface = new gfxImageSurface(gfxIntSize(1, 1), imageFormat);
     }
--- a/widget/src/qt/nsWindow.h
+++ b/widget/src/qt/nsWindow.h
@@ -106,17 +106,17 @@ class nsIdleService;
 
 class nsWindow : public nsBaseWidget,
                  public nsSupportsWeakReference
 {
 public:
     nsWindow();
     virtual ~nsWindow();
 
-    nsEventStatus DoPaint( QPainter* aPainter, const QStyleOptionGraphicsItem * aOption );
+    nsEventStatus DoPaint( QPainter* aPainter, const QStyleOptionGraphicsItem * aOption, QWidget* aWidget);
 
     static void ReleaseGlobals();
 
     NS_DECL_ISUPPORTS_INHERITED
 
     //
     // nsIWidget
     //
--- a/widget/src/shared/Makefile.in
+++ b/widget/src/shared/Makefile.in
@@ -52,17 +52,19 @@ DEFINES += \
   $(NULL)
 
 ifdef MOZ_X11
 PARALLEL_DIRS  = x11
 endif
 
 CPPSRCS		= \
 		WidgetUtils.cpp \
+		nsShmImage.cpp \
 		$(NULL)
 
 # we don't want the shared lib, but we want to force the creation of a static lib.
 FORCE_STATIC_LIB = 1
 
 include $(topsrcdir)/config/config.mk
+include $(topsrcdir)/ipc/chromium/chromium-config.mk
 include $(topsrcdir)/config/rules.mk
 
 CXXFLAGS	+= $(TK_CFLAGS)
new file mode 100644
--- /dev/null
+++ b/widget/src/shared/nsShmImage.cpp
@@ -0,0 +1,197 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Mozilla browser.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Chris Jones <jones.chris.g@gmail.com>
+ *   Oleg Romashin <romaxa@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#if defined(MOZ_WIDGET_GTK2)
+#include <gtk/gtk.h>
+#include <gdk/gdkx.h>
+#elif defined(MOZ_WIDGET_QT)
+#include <QWidget>
+#endif
+
+#include "nsShmImage.h"
+#include "gfxPlatform.h"
+#include "gfxImageSurface.h"
+
+#ifdef MOZ_HAVE_SHMIMAGE
+
+// If XShm isn't available to our client, we'll try XShm once, fail,
+// set this to false and then never try again.
+static PRBool gShmAvailable = PR_TRUE;
+PRBool nsShmImage::UseShm()
+{
+    return gfxPlatform::GetPlatform()->
+        ScreenReferenceSurface()->GetType() == gfxASurface::SurfaceTypeImage
+        && gShmAvailable;
+}
+
+already_AddRefed<nsShmImage>
+nsShmImage::Create(const gfxIntSize& aSize,
+                   Visual* aVisual, unsigned int aDepth)
+{
+    Display* dpy = DISPLAY();
+
+    nsRefPtr<nsShmImage> shm = new nsShmImage();
+    shm->mImage = XShmCreateImage(dpy, aVisual, aDepth,
+                                  ZPixmap, nsnull,
+                                  &(shm->mInfo),
+                                  aSize.width, aSize.height);
+    if (!shm->mImage) {
+        return nsnull;
+    }
+
+    size_t size = shm->mImage->bytes_per_line * shm->mImage->height;
+    shm->mSegment = new SharedMemorySysV();
+    if (!shm->mSegment->Create(size) || !shm->mSegment->Map(size)) {
+        return nsnull;
+    }
+
+    shm->mInfo.shmid = shm->mSegment->GetHandle();
+    shm->mInfo.shmaddr =
+        shm->mImage->data = static_cast<char*>(shm->mSegment->memory());
+    shm->mInfo.readOnly = False;
+
+    int xerror = 0;
+#if defined(MOZ_WIDGET_GTK2)
+    gdk_error_trap_push();
+    Status attachOk = XShmAttach(dpy, &shm->mInfo);
+    xerror = gdk_error_trap_pop();
+#elif defined(MOZ_WIDGET_QT)
+    Status attachOk = XShmAttach(dpy, &shm->mInfo);
+#endif
+
+    if (!attachOk || xerror) {
+        // Assume XShm isn't available, and don't attempt to use it
+        // again.
+        gShmAvailable = PR_FALSE;
+        return nsnull;
+    }
+
+    shm->mXAttached = PR_TRUE;
+    shm->mSize = aSize;
+    switch (shm->mImage->depth) {
+    case 24:
+        shm->mFormat = gfxASurface::ImageFormatRGB24; break;
+    case 16:
+        shm->mFormat = gfxASurface::ImageFormatRGB16_565; break;
+    default:
+        NS_WARNING("Unsupported XShm Image depth!");
+        gShmAvailable = PR_FALSE;
+        return nsnull;
+    }
+    return shm.forget();
+}
+
+already_AddRefed<gfxASurface>
+nsShmImage::AsSurface()
+{
+    return nsRefPtr<gfxASurface>(
+        new gfxImageSurface(static_cast<unsigned char*>(mSegment->memory()),
+                            mSize,
+                            mImage->bytes_per_line,
+                            mFormat)
+        ).forget();
+}
+
+#if defined(MOZ_WIDGET_GTK2)
+void
+nsShmImage::Put(GdkWindow* aWindow, GdkRectangle* aRects, GdkRectangle* aEnd)
+{
+    GdkDrawable* gd;
+    gint dx, dy;
+    gdk_window_get_internal_paint_info(aWindow, &gd, &dx, &dy);
+
+    Display* dpy = gdk_x11_get_default_xdisplay();
+    Drawable d = GDK_DRAWABLE_XID(gd);
+
+    GC gc = XCreateGC(dpy, d, 0, nsnull);
+    for (GdkRectangle* r = aRects; r < aEnd; r++) {
+        XShmPutImage(dpy, d, gc, mImage,
+                     r->x, r->y,
+                     r->x - dx, r->y - dy,
+                     r->width, r->height,
+                     False);
+    }
+    XFreeGC(dpy, gc);
+
+#ifdef MOZ_WIDGET_GTK2
+    // FIXME/bug 597336: we need to ensure that the shm image isn't
+    // scribbled over before all its pending XShmPutImage()s complete.
+    // However, XSync() is an unnecessarily heavyweight
+    // synchronization mechanism; other options are possible.  If this
+    // XSync is shown to hurt responsiveness, we need to explore the
+    // other options.
+    XSync(dpy, False);
+#endif
+}
+#elif defined(MOZ_WIDGET_QT)
+void
+nsShmImage::Put(QWidget* aWindow, QRect& aRect)
+{
+    Display* dpy = aWindow->x11Info().display();
+    Drawable d = aWindow->handle();
+
+    GC gc = XCreateGC(dpy, d, 0, nsnull);
+    // Avoid out of bounds painting
+    QRect inter = aRect.intersected(aWindow->rect());
+    XShmPutImage(dpy, d, gc, mImage,
+                 inter.x(), inter.y(),
+                 inter.x(), inter.y(),
+                 inter.width(), inter.height(),
+                 False);
+    XFreeGC(dpy, gc);
+}
+#endif
+
+already_AddRefed<gfxASurface>
+nsShmImage::EnsureShmImage(const gfxIntSize& aSize, Visual* aVisual, unsigned int aDepth,
+               nsRefPtr<nsShmImage>& aImage)
+{
+    if (!aImage || aImage->Size() != aSize) {
+        // Because we XSync() after XShmAttach() to trap errors, we
+        // know that the X server has the old image's memory mapped
+        // into its address space, so it's OK to destroy the old image
+        // here even if there are outstanding Puts.  The Detach is
+        // ordered after the Puts.
+        aImage = nsShmImage::Create(aSize, aVisual, aDepth);
+    }
+    return !aImage ? nsnull : aImage->AsSurface();
+}
+
+#endif  // defined(MOZ_X11) && defined(MOZ_HAVE_SHAREDMEMORYSYSV)
new file mode 100644
--- /dev/null
+++ b/widget/src/shared/nsShmImage.h
@@ -0,0 +1,122 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Mozilla browser.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Chris Jones <jones.chris.g@gmail.com>
+ *   Oleg Romashin <romaxa@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef __mozilla_widget_nsShmImage_h__
+#define __mozilla_widget_nsShmImage_h__
+
+#ifdef MOZ_IPC
+#  include "mozilla/ipc/SharedMemorySysV.h"
+#endif
+
+#if defined(MOZ_X11) && defined(MOZ_HAVE_SHAREDMEMORYSYSV)
+#  define MOZ_HAVE_SHMIMAGE
+#endif
+
+#ifdef MOZ_HAVE_SHMIMAGE
+
+#include "nsIWidget.h"
+#include "gfxASurface.h"
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/extensions/XShm.h>
+
+#if defined(MOZ_WIDGET_GTK2)
+#define DISPLAY gdk_x11_get_default_xdisplay
+#elif defined(MOZ_WIDGET_QT)
+#include "QX11Info"
+#define DISPLAY QX11Info().display
+#endif
+
+class QRect;
+class QWidget;
+
+using mozilla::ipc::SharedMemorySysV;
+
+class nsShmImage {
+    NS_INLINE_DECL_REFCOUNTING(nsShmImage)
+
+public:
+    typedef gfxASurface::gfxImageFormat Format;
+
+    static PRBool UseShm();
+    static already_AddRefed<nsShmImage>
+        Create(const gfxIntSize& aSize, Visual* aVisual, unsigned int aDepth);
+    static already_AddRefed<gfxASurface>
+        EnsureShmImage(const gfxIntSize& aSize, Visual* aVisual, unsigned int aDepth,
+                       nsRefPtr<nsShmImage>& aImage);
+
+    ~nsShmImage() {
+        if (mImage) {
+            XSync(DISPLAY(), False);
+            if (mXAttached) {
+                XShmDetach(DISPLAY(), &mInfo);
+            }
+            XDestroyImage(mImage);
+        }
+    }
+
+    already_AddRefed<gfxASurface> AsSurface();
+
+#if defined(MOZ_WIDGET_GTK2)
+    void Put(GdkWindow* aWindow, GdkRectangle* aRects, GdkRectangle* aEnd);
+#elif defined(MOZ_WIDGET_QT)
+    void Put(QWidget* aWindow, QRect& aRect);
+#endif
+
+    gfxIntSize Size() const { return mSize; }
+
+private:
+    nsShmImage()
+        : mImage(nsnull)
+        , mXAttached(PR_FALSE)
+    { mInfo.shmid = SharedMemorySysV::NULLHandle(); }
+
+    nsRefPtr<SharedMemorySysV>   mSegment;
+    XImage*                      mImage;
+    XShmSegmentInfo              mInfo;
+    gfxIntSize                   mSize;
+    Format                       mFormat;
+    PRPackedBool                 mXAttached;
+};
+
+#endif // MOZ_HAVE_SHMIMAGE
+
+#endif