diff --git a/gfx/thebes/gfxQtPlatform.cpp b/gfx/thebes/gfxQtPlatform.cpp index 746e3dd21df..fda8382a9dc 100644 --- a/gfx/thebes/gfxQtPlatform.cpp +++ b/gfx/thebes/gfxQtPlatform.cpp @@ -81,7 +81,11 @@ // 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; @@ -146,6 +150,9 @@ gfxQtPlatform::gfxQtPlatform() case 1: mRenderMode = RENDER_BUFFERED; break; + case 2: + mRenderMode = RENDER_DIRECT; + break; default: mRenderMode = RENDER_QPAINTER; } @@ -207,7 +214,7 @@ gfxQtPlatform::CreateOffscreenSurface(const gfxIntSize& size, } #endif - if (mRenderMode == RENDER_BUFFERED && + if ((mRenderMode == RENDER_BUFFERED || mRenderMode == RENDER_DIRECT) && sDefaultQtPaintEngineType != QPaintEngine::X11) { newSurface = new gfxImageSurface(size, imageFormat); return newSurface.forget(); diff --git a/gfx/thebes/gfxQtPlatform.h b/gfx/thebes/gfxQtPlatform.h index 584f1797664..994f71fe3ee 100644 --- a/gfx/thebes/gfxQtPlatform.h +++ b/gfx/thebes/gfxQtPlatform.h @@ -60,6 +60,8 @@ public: 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 }; diff --git a/widget/src/gtk2/nsWindow.cpp b/widget/src/gtk2/nsWindow.cpp index 1656e615d9d..bdffbc01806 100644 --- a/widget/src/gtk2/nsWindow.cpp +++ b/widget/src/gtk2/nsWindow.cpp @@ -135,6 +135,8 @@ extern "C" { #include "gfxXlibSurface.h" #endif +#include "nsShmImage.h" + #ifdef MOZ_DFB extern "C" { #ifdef MOZ_DIRECT_DEBUG @@ -286,16 +288,6 @@ UpdateLastInputEventTime() } } -#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; @@ -389,159 +381,6 @@ protected: 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 - 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 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 mSegment; - XImage* mImage; - XShmSegmentInfo mInfo; - gfxIntSize mSize; - Format mFormat; - PRPackedBool mXAttached; -}; - -already_AddRefed -nsShmImage::Create(const gfxIntSize& aSize, - Visual* aVisual, unsigned int aDepth) -{ - Display* dpy = gdk_x11_get_default_xdisplay(); - - nsRefPtr 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(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 -nsShmImage::AsSurface() -{ - return nsRefPtr( - new gfxImageSurface(static_cast(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 -EnsureShmImage(const gfxIntSize& aSize, Visual* aVisual, unsigned int aDepth, - nsRefPtr& 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; @@ -2346,7 +2185,7 @@ nsWindow::OnExposeEvent(GtkWidget *aWidget, GdkEventExpose *aEvent) 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 @@ -2405,7 +2244,7 @@ nsWindow::OnExposeEvent(GtkWidget *aWidget, GdkEventExpose *aEvent) } } # 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 @@ -6706,13 +6545,14 @@ nsWindow::GetThebesSurface() # 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) diff --git a/widget/src/qt/Makefile.in b/widget/src/qt/Makefile.in index 4aca0cf957c..de7403af097 100644 --- a/widget/src/qt/Makefile.in +++ b/widget/src/qt/Makefile.in @@ -103,6 +103,8 @@ 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) @@ -131,4 +133,5 @@ LOCAL_INCLUDES += \ $(NULL) ifdef MOZ_X11 INCLUDES += -I$(srcdir)/../shared/x11 +INCLUDES += -I$(srcdir)/../shared endif diff --git a/widget/src/qt/mozqwidget.cpp b/widget/src/qt/mozqwidget.cpp index 1daea9ab89a..b66959cab89 100644 --- a/widget/src/qt/mozqwidget.cpp +++ b/widget/src/qt/mozqwidget.cpp @@ -92,7 +92,7 @@ MozQWidget::~MozQWidget() void MozQWidget::paint(QPainter* aPainter, const QStyleOptionGraphicsItem* aOption, QWidget* aWidget /*= 0*/) { - mReceiver->DoPaint(aPainter, aOption); + mReceiver->DoPaint(aPainter, aOption, aWidget); } void MozQWidget::activate() diff --git a/widget/src/qt/nsWindow.cpp b/widget/src/qt/nsWindow.cpp index 3d96219f2ea..698f7964fda 100644 --- a/widget/src/qt/nsWindow.cpp +++ b/widget/src/qt/nsWindow.cpp @@ -128,11 +128,22 @@ static const float GESTURES_BLOCK_MOUSE_FOR = 200; #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 gBufferSurface; +#ifdef MOZ_HAVE_SHMIMAGE +// If we're using xshm rendering, mThebesSurface wraps gShmImage +nsRefPtr gShmImage; +#endif static int gBufferPixmapUsageCount = 0; static gfxIntSize gBufferMaxSize(0, 0); @@ -268,7 +279,7 @@ _gfximage_to_qformat(gfxASurface::gfxImageFormat aFormat) } static bool -UpdateOffScreenBuffers(int aDepth, QSize aSize) +UpdateOffScreenBuffers(int aDepth, QSize aSize, QWidget* aWidget = nsnull) { gfxIntSize size(aSize.width(), aSize.height()); if (gBufferSurface) { @@ -290,8 +301,22 @@ UpdateOffScreenBuffers(int aDepth, QSize aSize) 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; } @@ -343,6 +368,9 @@ nsWindow::Destroy(void) --gBufferPixmapUsageCount == 0) { gBufferSurface = nsnull; +#ifdef MOZ_HAVE_SHMIMAGE + gShmImage = nsnull; +#endif } nsCOMPtr rollupWidget = do_QueryReferent(gRollupWindow); @@ -941,8 +969,23 @@ nsWindow::GetAttention(PRInt32 aCycleCount) return NS_ERROR_NOT_IMPLEMENTED; } +#ifdef MOZ_X11 +static already_AddRefed +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", @@ -993,6 +1036,11 @@ nsWindow::DoPaint(QPainter* aPainter, const QStyleOptionGraphicsItem* aOption) } 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)) @@ -1001,17 +1049,30 @@ nsWindow::DoPaint(QPainter* aPainter, const QStyleOptionGraphicsItem* aOption) nsRefPtr 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 @@ -1047,6 +1108,30 @@ nsWindow::DoPaint(QPainter* aPainter, const QStyleOptionGraphicsItem* aOption) 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 widgetSurface = GetSurfaceForQWidget(aWidget); + nsRefPtr 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 widgetSurface = GetSurfaceForQWidget(aWidget); + nsRefPtr 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; @@ -2475,6 +2560,11 @@ nsWindow::createQWidget(MozQWidget *parent, nsWidgetInitData *aInitData) 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); @@ -2528,8 +2618,8 @@ nsWindow::GetThebesSurface() if (mThebesSurface) return mThebesSurface; - gfxQtPlatform::RenderMode renderMode = gfxQtPlatform::GetPlatform()->GetRenderMode(); #ifdef CAIRO_HAS_QT_SURFACE + gfxQtPlatform::RenderMode renderMode = gfxQtPlatform::GetPlatform()->GetRenderMode(); if (renderMode == gfxQtPlatform::RENDER_QPAINTER) { mThebesSurface = new gfxQPainterSurface(gfxIntSize(1, 1), gfxASurface::CONTENT_COLOR); } diff --git a/widget/src/qt/nsWindow.h b/widget/src/qt/nsWindow.h index 6d3b340bad7..9cddee5807b 100644 --- a/widget/src/qt/nsWindow.h +++ b/widget/src/qt/nsWindow.h @@ -111,7 +111,7 @@ public: nsWindow(); virtual ~nsWindow(); - nsEventStatus DoPaint( QPainter* aPainter, const QStyleOptionGraphicsItem * aOption ); + nsEventStatus DoPaint( QPainter* aPainter, const QStyleOptionGraphicsItem * aOption, QWidget* aWidget); static void ReleaseGlobals(); diff --git a/widget/src/shared/Makefile.in b/widget/src/shared/Makefile.in index 52a52f645af..a111ac124ff 100644 --- a/widget/src/shared/Makefile.in +++ b/widget/src/shared/Makefile.in @@ -57,12 +57,14 @@ 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) diff --git a/widget/src/shared/nsShmImage.cpp b/widget/src/shared/nsShmImage.cpp new file mode 100644 index 00000000000..bf9b7e3bb81 --- /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 + * Oleg Romashin + * + * 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 +#include +#elif defined(MOZ_WIDGET_QT) +#include +#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::Create(const gfxIntSize& aSize, + Visual* aVisual, unsigned int aDepth) +{ + Display* dpy = DISPLAY(); + + nsRefPtr 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(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 +nsShmImage::AsSurface() +{ + return nsRefPtr( + new gfxImageSurface(static_cast(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 +nsShmImage::EnsureShmImage(const gfxIntSize& aSize, Visual* aVisual, unsigned int aDepth, + nsRefPtr& 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) diff --git a/widget/src/shared/nsShmImage.h b/widget/src/shared/nsShmImage.h new file mode 100644 index 00000000000..52e1ae32612 --- /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 + * Oleg Romashin + * + * 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 +#include +#include + +#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 + Create(const gfxIntSize& aSize, Visual* aVisual, unsigned int aDepth); + static already_AddRefed + EnsureShmImage(const gfxIntSize& aSize, Visual* aVisual, unsigned int aDepth, + nsRefPtr& aImage); + + ~nsShmImage() { + if (mImage) { + XSync(DISPLAY(), False); + if (mXAttached) { + XShmDetach(DISPLAY(), &mInfo); + } + XDestroyImage(mImage); + } + } + + already_AddRefed 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 mSegment; + XImage* mImage; + XShmSegmentInfo mInfo; + gfxIntSize mSize; + Format mFormat; + PRPackedBool mXAttached; +}; + +#endif // MOZ_HAVE_SHMIMAGE + +#endif