Bug 606910 - RENDER_DIRECT mode for Qt widget (xshmPutImage). r=dougt a=blocking-fennec

--HG--
extra : rebase_source : 6ea776ea7e0b282d6b61d5e5fa570460e84f90be
This commit is contained in:
Oleg Romashin 2010-10-27 07:56:31 +03:00
Родитель 6d4b7edaf4
Коммит 35d0416872
10 изменённых файлов: 444 добавлений и 181 удалений

Просмотреть файл

@ -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();

Просмотреть файл

@ -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
};

Просмотреть файл

@ -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<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;
@ -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)

Просмотреть файл

@ -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

Просмотреть файл

@ -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()

Просмотреть файл

@ -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<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);
@ -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<nsIWidget> rollupWidget = do_QueryReferent(gRollupWindow);
@ -941,8 +969,23 @@ nsWindow::GetAttention(PRInt32 aCycleCount)
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",
@ -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<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
@ -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<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;
@ -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);
}

Просмотреть файл

@ -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();

Просмотреть файл

@ -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)

Просмотреть файл

@ -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)

Просмотреть файл

@ -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