Bug 544250 - Implement different rendering backends for Qt mozilla port. r=jmuizelaar

This commit is contained in:
Oleg Romashin 2010-02-16 10:15:52 -08:00
parent 4cedcaea21
commit 5cfa8aef3e
9 changed files with 384 additions and 19 deletions

View File

@ -32,6 +32,10 @@ EXPORTS = gfxASurface.h \
gfxUserFontSet.h \
$(NULL)
EXPORTS += \
gfxSharedImageSurface.h \
$(NULL)
EXPORTS += gfxFontTest.h
ifeq ($(MOZ_WIDGET_TOOLKIT),windows)

View File

@ -51,6 +51,18 @@ class FontEntry;
class THEBES_API gfxQtPlatform : public gfxPlatform {
public:
enum RenderMode {
/* Use QPainter surfaces */
RENDER_QPAINTER = 0,
/* Use Xlib surface to render and wrap as QPixmap */
RENDER_XLIB,
/* Use image surfaces and XShmPutImage to QPixmap */
RENDER_SHARED_IMAGE,
/* max */
RENDER_MODE_MAX
};
gfxQtPlatform();
virtual ~gfxQtPlatform();
@ -87,6 +99,9 @@ public:
FT_Library GetFTLibrary();
RenderMode GetRenderMode() { return mRenderMode; }
void SetRenderMode(RenderMode rmode) { mRenderMode = rmode; }
protected:
static gfxFontconfigUtils *sFontconfigUtils;
@ -96,6 +111,7 @@ private:
// TODO: unify this with mPrefFonts (NB: holds families, not fonts) in gfxPlatformFontList
nsDataHashtable<nsCStringHashKey, nsTArray<nsRefPtr<gfxFontEntry> > > mPrefFonts;
RenderMode mRenderMode;
};
#endif /* GFX_PLATFORM_QT_H */

View File

@ -34,6 +34,10 @@ CPPSRCS = \
gfxUserFontSet.cpp \
$(NULL)
CPPSRCS += \
gfxSharedImageSurface.cpp \
$(NULL)
EXTRA_DSO_LDOPTS += \
$(MOZ_CAIRO_LIBS) \
$(MOZ_UNICHARUTIL_LIBS) \

View File

@ -58,12 +58,20 @@
#include "nsMathUtils.h"
#include "nsTArray.h"
#ifdef MOZ_X11
#include "gfxXlibSurface.h"
#endif
#include "qcms.h"
#include <ft2build.h>
#include FT_FREETYPE_H
#include "nsIPrefBranch.h"
#include "nsIPrefService.h"
#define DEFAULT_RENDER_MODE RENDER_SHARED_IMAGE
gfxFontconfigUtils *gfxQtPlatform::sFontconfigUtils = nsnull;
static cairo_user_data_key_t cairo_qt_pixmap_key;
static void do_qt_pixmap_unref (void *data)
@ -99,6 +107,36 @@ gfxQtPlatform::gfxQtPlatform()
gPrefFonts->Init(100);
gCodepointsWithNoFonts = new gfxSparseBitSet();
UpdateFontList();
nsresult rv;
PRInt32 ival;
// 0 - default gfxQPainterSurface
// 1 - gfxXlibSurface
// 2 - gfxImageSurface
nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
if (prefs) {
rv = prefs->GetIntPref("mozilla.widget-qt.render-mode", &ival);
if (NS_FAILED(rv))
ival = DEFAULT_RENDER_MODE;
}
const char *envTypeOverride = getenv("MOZ_QT_RENDER_TYPE");
if (envTypeOverride)
ival = atoi(envTypeOverride);
switch (ival) {
case 0:
mRenderMode = RENDER_QPAINTER;
break;
case 1:
mRenderMode = RENDER_XLIB;
break;
case 2:
mRenderMode = RENDER_SHARED_IMAGE;
break;
default:
mRenderMode = RENDER_QPAINTER;
}
}
gfxQtPlatform::~gfxQtPlatform()
@ -134,8 +172,53 @@ already_AddRefed<gfxASurface>
gfxQtPlatform::CreateOffscreenSurface(const gfxIntSize& size,
gfxASurface::gfxImageFormat imageFormat)
{
nsRefPtr<gfxASurface> newSurface =
new gfxQPainterSurface (size, gfxASurface::ContentFromFormat(imageFormat));
nsRefPtr<gfxASurface> newSurface = nsnull;
if (mRenderMode == RENDER_QPAINTER) {
newSurface = new gfxQPainterSurface(size, gfxASurface::ContentFromFormat(imageFormat));
return newSurface.forget();
}
if (mRenderMode == RENDER_SHARED_IMAGE) {
newSurface = new gfxImageSurface(size, imageFormat);
return newSurface.forget();
}
#ifdef MOZ_X11
int xrenderFormatID = -1;
switch (imageFormat) {
case gfxASurface::ImageFormatARGB32:
xrenderFormatID = PictStandardARGB32;
break;
case gfxASurface::ImageFormatRGB24:
xrenderFormatID = PictStandardRGB24;
break;
case gfxASurface::ImageFormatA8:
xrenderFormatID = PictStandardA8;
break;
case gfxASurface::ImageFormatA1:
xrenderFormatID = PictStandardA1;
break;
default:
return nsnull;
}
// XXX we really need a different interface here, something that passes
// in more context, including the display and/or target surface type that
// we should try to match
XRenderPictFormat* xrenderFormat =
XRenderFindStandardFormat(QX11Info().display(), xrenderFormatID);
newSurface = new gfxXlibSurface((Display*)QX11Info().display(),
xrenderFormat,
size);
#endif
if (newSurface) {
gfxContext ctx(newSurface);
ctx.SetOperator(gfxContext::OPERATOR_CLEAR);
ctx.Paint();
}
return newSurface.forget();
}

View File

@ -257,7 +257,7 @@ EXTRA_DSO_LDOPTS += -ljprof
endif
ifdef MOZ_ENABLE_QT
EXTRA_DSO_LDOPTS += $(MOZ_QT_LDFLAGS)
EXTRA_DSO_LDOPTS += $(MOZ_QT_LDFLAGS) $(XEXT_LIBS)
endif
include $(topsrcdir)/config/rules.mk

View File

@ -104,8 +104,8 @@ endif
include $(topsrcdir)/config/rules.mk
CXXFLAGS += $(MOZ_QT_CFLAGS) $(GLIB_CFLAGS)
CFLAGS += $(MOZ_QT_CFLAGS) $(GLIB_CFLAGS)
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

View File

@ -69,7 +69,11 @@
#include "gfxASurface.h"
#include "gfxContext.h"
#include "gfxQtPlatform.h"
#include "gfxQPainterSurface.h"
#ifdef MOZ_X11
#include "gfxXlibSurface.h"
#endif
#include "nsIRenderingContext.h"
nsNativeThemeQt::nsNativeThemeQt()
@ -93,6 +97,29 @@ static inline QRect qRectInPixels(const nsRect &aRect,
NSAppUnitsToIntPixels(aRect.height, p2a));
}
static inline QImage::Format
_qimage_from_gfximage_format (gfxASurface::gfxImageFormat aFormat)
{
switch (aFormat) {
case gfxASurface::ImageFormatARGB32:
return QImage::Format_ARGB32_Premultiplied;
case gfxASurface::ImageFormatRGB24:
return QImage::Format_RGB32;
case gfxASurface::ImageFormatA8:
return QImage::Format_Indexed8;
case gfxASurface::ImageFormatA1:
#ifdef WORDS_BIGENDIAN
return QImage::Format_Mono;
#else
return QImage::Format_MonoLSB;
#endif
default:
return QImage::Format_Invalid;
}
return QImage::Format_Mono;
}
NS_IMETHODIMP
nsNativeThemeQt::DrawWidgetBackground(nsIRenderingContext* aContext,
nsIFrame* aFrame,
@ -103,19 +130,56 @@ nsNativeThemeQt::DrawWidgetBackground(nsIRenderingContext* aContext,
gfxContext* context = aContext->ThebesContext();
nsRefPtr<gfxASurface> surface = context->CurrentSurface();
if (surface->GetType() == gfxASurface::SurfaceTypeQPainter) {
gfxQPainterSurface* qSurface = (gfxQPainterSurface*) (surface.get());
QPainter *painter = qSurface->GetQPainter();
NS_ASSERTION(painter, "Where'd my QPainter go?");
if (!painter)
return NS_ERROR_FAILURE;
return DrawWidgetBackground(painter, aContext,
aFrame, aWidgetType,
aRect, aClipRect);
}
else if (surface->GetType() == gfxASurface::SurfaceTypeImage) {
gfxImageSurface* qSurface = (gfxImageSurface*) (surface.get());
QImage tempQImage(qSurface->Data(),
qSurface->Width(),
qSurface->Height(),
qSurface->Stride(),
_qimage_from_gfximage_format(qSurface->Format()));
QPainter painter(&tempQImage);
return DrawWidgetBackground(&painter, aContext,
aFrame, aWidgetType,
aRect, aClipRect);
}
#ifdef MOZ_X11
else if (surface->GetType() == gfxASurface::SurfaceTypeXlib) {
gfxXlibSurface* qSurface = (gfxXlibSurface*) (surface.get());
QPixmap pixmap(QPixmap::fromX11Pixmap(qSurface->XDrawable()));
QPainter painter(&pixmap);
return DrawWidgetBackground(&painter, aContext,
aFrame, aWidgetType,
aRect, aClipRect);
}
#endif
return NS_ERROR_NOT_IMPLEMENTED;
}
nsresult
nsNativeThemeQt::DrawWidgetBackground(QPainter *qPainter,
nsIRenderingContext* aContext,
nsIFrame* aFrame,
PRUint8 aWidgetType,
const nsRect& aRect,
const nsRect& aClipRect)
{
gfxContext* context = aContext->ThebesContext();
nsRefPtr<gfxASurface> surface = context->CurrentSurface();
context->UpdateSurfaceClip();
if (surface->GetType() != gfxASurface::SurfaceTypeQPainter)
return NS_ERROR_NOT_IMPLEMENTED;
gfxQPainterSurface* qSurface = (gfxQPainterSurface*) (surface.get());
QPainter* qPainter = qSurface->GetQPainter();
NS_ASSERTION(qPainter, "Where'd my QPainter go?");
if (qPainter == nsnull)
return NS_OK;
QStyle* style = qApp->style();
qPainter->save();

View File

@ -106,6 +106,13 @@ public:
private:
inline nsresult DrawWidgetBackground(QPainter *qPainter,
nsIRenderingContext* aContext,
nsIFrame* aFrame,
PRUint8 aWidgetType,
const nsRect& aRect,
const nsRect& aClipRect);
inline PRInt32 GetAppUnitsPerDevPixel(nsIRenderingContext* aContext){
nsCOMPtr<nsIDeviceContext> dctx = nsnull;
aContext->GetDeviceContext(*getter_AddRefs(dctx));

View File

@ -89,7 +89,19 @@
#include "gfxXlibSurface.h"
#include "gfxQPainterSurface.h"
#include "gfxContext.h"
#include "gfxSharedImageSurface.h"
// Buffered Pixmap stuff
static QPixmap *gBufferPixmap = nsnull;
static int gBufferPixmapUsageCount = 0;
// Buffered shared image + pixmap
static gfxSharedImageSurface *gBufferImage = nsnull;
static gfxSharedImageSurface *gBufferImageTemp = nsnull;
PRBool gNeedColorConversion = PR_FALSE;
extern "C" {
#include "pixman.h"
}
/* For PrepareNativeWidget */
static NS_DEFINE_IID(kDeviceContextCID, NS_DEVICE_CONTEXT_CID);
@ -175,6 +187,90 @@ nsWindow::nsWindow()
mIsTransparent = PR_FALSE;
mCursor = eCursor_standard;
gBufferPixmapUsageCount++;
}
static inline gfxASurface::gfxImageFormat
_depth_to_gfximage_format(PRInt32 aDepth)
{
switch (aDepth) {
case 32:
return gfxASurface::ImageFormatARGB32;
case 24:
return gfxASurface::ImageFormatRGB24;
default:
return gfxASurface::ImageFormatUnknown;
}
}
static void
FreeOffScreenBuffers(void)
{
delete gBufferImage;
delete gBufferImageTemp;
delete gBufferPixmap;
gBufferImage = nsnull;
gBufferImageTemp = nsnull;
gBufferPixmap = nsnull;
}
static bool
UpdateOffScreenBuffers(QSize aSize, int aDepth)
{
gfxIntSize size(aSize.width(), aSize.height());
if (gBufferPixmap) {
if (gBufferPixmap->size().width() < size.width ||
gBufferPixmap->size().height() < size.height) {
FreeOffScreenBuffers();
} else
return true;
}
gBufferPixmap = new QPixmap(size.width, size.height);
if (!gBufferPixmap)
return false;
if (gfxQtPlatform::GetPlatform()->GetRenderMode() == gfxQtPlatform::RENDER_XLIB)
return true;
// Check if system depth has related gfxImage format
gfxASurface::gfxImageFormat format =
_depth_to_gfximage_format(gBufferPixmap->x11Info().depth());
gNeedColorConversion = (format == gfxASurface::ImageFormatUnknown);
gBufferImage = new gfxSharedImageSurface();
if (!gBufferImage) {
FreeOffScreenBuffers();
return false;
}
if (!gBufferImage->Init(gfxIntSize(gBufferPixmap->size().width(),
gBufferPixmap->size().height()),
_depth_to_gfximage_format(gBufferPixmap->x11Info().depth()))) {
FreeOffScreenBuffers();
return false;
}
// gfxImageSurface does not support system color depth format
// we have to paint it with temp surface and color conversion
if (!gNeedColorConversion)
return true;
gBufferImageTemp = new gfxSharedImageSurface();
if (!gBufferImageTemp) {
FreeOffScreenBuffers();
return false;
}
if (!gBufferImageTemp->Init(gfxIntSize(gBufferPixmap->size().width(),
gBufferPixmap->size().height()),
gfxASurface::ImageFormatRGB24)) {
FreeOffScreenBuffers();
return false;
}
return true;
}
nsWindow::~nsWindow()
@ -221,6 +317,12 @@ nsWindow::Destroy(void)
LOG(("nsWindow::Destroy [%p]\n", (void *)this));
mIsDestroyed = PR_TRUE;
if (gBufferPixmapUsageCount &&
--gBufferPixmapUsageCount == 0) {
FreeOffScreenBuffers();
}
nsCOMPtr<nsIWidget> rollupWidget = do_QueryReferent(gRollupWindow);
if (static_cast<nsIWidget *>(this) == rollupWidget.get()) {
if (gRollupListener)
@ -830,6 +932,20 @@ nsWindow::GetAttention(PRInt32 aCycleCount)
return NS_ERROR_NOT_IMPLEMENTED;
}
#ifdef MOZ_X11
static already_AddRefed<gfxASurface>
GetSurfaceForQWidget(QPixmap* 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)
{
@ -857,7 +973,25 @@ nsWindow::DoPaint(QPainter* aPainter, const QStyleOptionGraphicsItem* aOption)
updateRegion->SetTo( (int)r.x(), (int)r.y(), (int)r.width(), (int)r.height() );
nsRefPtr<gfxASurface> targetSurface = new gfxQPainterSurface(aPainter);
gfxQtPlatform::RenderMode renderMode = gfxQtPlatform::GetPlatform()->GetRenderMode();
// Prepare offscreen buffers if RenderMode Xlib or Image
if (renderMode != gfxQtPlatform::RENDER_QPAINTER)
if (!UpdateOffScreenBuffers(r.size().toSize(), QX11Info().depth()))
return nsEventStatus_eIgnore;
nsRefPtr<gfxASurface> targetSurface = nsnull;
if (renderMode == gfxQtPlatform::RENDER_XLIB) {
targetSurface = GetSurfaceForQWidget(gBufferPixmap);
} else if (renderMode == gfxQtPlatform::RENDER_SHARED_IMAGE) {
targetSurface = gNeedColorConversion ? gBufferImageTemp->getASurface()
: gBufferImage->getASurface();
} else if (renderMode == gfxQtPlatform::RENDER_QPAINTER) {
targetSurface = new gfxQPainterSurface(aPainter);
}
if (NS_UNLIKELY(!targetSurface))
return nsEventStatus_eIgnore;
nsRefPtr<gfxContext> ctx = new gfxContext(targetSurface);
nsCOMPtr<nsIRenderingContext> rc;
@ -888,6 +1022,46 @@ nsWindow::DoPaint(QPainter* aPainter, const QStyleOptionGraphicsItem* aOption)
LOGDRAW(("[%p] draw done\n", this));
if (renderMode == gfxQtPlatform::RENDER_SHARED_IMAGE) {
if (gNeedColorConversion) {
pixman_image_t *src_image = NULL;
pixman_image_t *dst_image = NULL;
src_image = pixman_image_create_bits(PIXMAN_x8r8g8b8,
gBufferImageTemp->GetSize().width,
gBufferImageTemp->GetSize().height,
(uint32_t*)gBufferImageTemp->Data(),
gBufferImageTemp->Stride());
dst_image = pixman_image_create_bits(PIXMAN_r5g6b5,
gBufferImage->GetSize().width,
gBufferImage->GetSize().height,
(uint32_t*)gBufferImage->Data(),
gBufferImage->Stride());
pixman_image_composite(PIXMAN_OP_SRC,
src_image,
NULL,
dst_image,
0, 0,
0, 0,
0, 0,
gBufferImageTemp->GetSize().width,
gBufferImageTemp->GetSize().height);
pixman_image_unref(src_image);
pixman_image_unref(dst_image);
}
Display *disp = gBufferPixmap->x11Info().display();
XGCValues gcv;
gcv.graphics_exposures = False;
GC gc = XCreateGC (disp, gBufferPixmap->handle(), GCGraphicsExposures, &gcv);
XShmPutImage(disp, gBufferPixmap->handle(), gc, gBufferImage->image(),
0, 0, 0, 0, gBufferImage->GetSize().width, gBufferImage->GetSize().height,
False);
XFreeGC (disp, gc);
}
if (renderMode != gfxQtPlatform::RENDER_QPAINTER)
aPainter->drawPixmap(QPoint(0, 0), *gBufferPixmap);
ctx = nsnull;
targetSurface = nsnull;
@ -1804,8 +1978,21 @@ 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)
mThebesSurface = new gfxQPainterSurface(gfxIntSize(5,5), gfxASurface::CONTENT_COLOR);
if (mThebesSurface)
return mThebesSurface;
gfxQtPlatform::RenderMode renderMode = gfxQtPlatform::GetPlatform()->GetRenderMode();
if (renderMode == gfxQtPlatform::RENDER_QPAINTER) {
mThebesSurface = new gfxQPainterSurface(gfxIntSize(1, 1), gfxASurface::CONTENT_COLOR);
} else if (renderMode == gfxQtPlatform::RENDER_XLIB) {
mThebesSurface = new gfxXlibSurface(QX11Info().display(),
(Visual*)QX11Info().visual(),
gfxIntSize(1, 1), QX11Info().depth());
}
if (!mThebesSurface) {
gfxASurface::gfxImageFormat imageFormat = gfxASurface::ImageFormatRGB24;
mThebesSurface = new gfxImageSurface(gfxIntSize(1, 1), imageFormat);
}
return mThebesSurface;
}