From 81c940994cd9d36bda5b6688e4a6192fb7f5b60c Mon Sep 17 00:00:00 2001 From: "vladimir%pobox.com" Date: Mon, 16 Aug 2004 00:37:37 +0000 Subject: [PATCH] better cairo drawing surface stuff, in progress --- gfx/src/cairo/nsCairoDeviceContext.cpp | 28 ++++ gfx/src/cairo/nsCairoDeviceContext.h | 12 +- gfx/src/cairo/nsCairoDrawingSurface.cpp | 169 ++++++++++++++++++------ gfx/src/cairo/nsCairoDrawingSurface.h | 32 +++-- 4 files changed, 185 insertions(+), 56 deletions(-) diff --git a/gfx/src/cairo/nsCairoDeviceContext.cpp b/gfx/src/cairo/nsCairoDeviceContext.cpp index 297c66665110..bd89b058a187 100644 --- a/gfx/src/cairo/nsCairoDeviceContext.cpp +++ b/gfx/src/cairo/nsCairoDeviceContext.cpp @@ -392,3 +392,31 @@ nsCairoDeviceContext::SetUseAltDC(PRUint8 aValue, PRBool aOn) return NS_OK; } +#if defined(MOZ_ENABLE_GTK2) || defined(MOZ_ENABLE_XLIB) +Display * +nsCairoDeviceContext::GetXDisplay() +{ +#ifdef MOZ_ENABLE_GTK2 + return gdk_x11_get_default_xdisplay(); +#endif +} + +Visual * +nsCairoDeviceContext::GetXVisual() +{ + return DefaultVisual(GetXDisplay(),DefaultScreen(GetXDisplay())); +} + +Colormap +nsCairoDeviceContext::GetXColormap() +{ + return DefaultColormap(GetXDisplay(),DefaultScreen(GetXDisplay())); +} + +Drawable +nsCairoDeviceContext::GetXPixmapParentDrawable() +{ + return RootWindow(GetXDisplay(),DefaultScreen(GetXDisplay())); +} + +#endif diff --git a/gfx/src/cairo/nsCairoDeviceContext.h b/gfx/src/cairo/nsCairoDeviceContext.h index 3f1a3feee71c..dc5593491856 100644 --- a/gfx/src/cairo/nsCairoDeviceContext.h +++ b/gfx/src/cairo/nsCairoDeviceContext.h @@ -97,15 +97,25 @@ public: NS_IMETHOD GetAltDevice(nsIDeviceContext** aAltDC); NS_IMETHOD SetUseAltDC(PRUint8 aValue, PRBool aOn); - // local methods NS_IMETHOD CreateCairoFor(nsNativeWidget aNativeWidget, cairo_t **aCairo); +#if defined(MOZ_ENABLE_GTK2) || defined(MOZ_ENABLE_XLIB) + Display *GetXDisplay(); + Visual *GetXVisual(); + Colormap GetXColormap(); + Drawable GetXPixmapParentDrawable(); +#endif + private: cairo_t *mCairo; cairo_surface_t *mSurface; nsNativeWidget mWidget; +#if defined(MOZ_ENABLE_GTK2) || defined(MOZ_ENABLE_XLIB) + Drawable mPixmapParentDrawable; +#endif + #ifdef MOZ_ENABLE_XLIB XlibRgbHandle *mXlibRgbHandle; #endif diff --git a/gfx/src/cairo/nsCairoDrawingSurface.cpp b/gfx/src/cairo/nsCairoDrawingSurface.cpp index e512544297a0..53a1bbc94f94 100644 --- a/gfx/src/cairo/nsCairoDrawingSurface.cpp +++ b/gfx/src/cairo/nsCairoDrawingSurface.cpp @@ -43,63 +43,102 @@ NS_IMPL_ISUPPORTS1(nsCairoDrawingSurface, nsIDrawingSurface) nsCairoDrawingSurface::nsCairoDrawingSurface() - : mSurface(nsnull), mSurfaceData(nsnull), mOwnsData(PR_FALSE) + : mSurface(nsnull), mImageSurface(nsnull), mSurfaceData(nsnull), mOwnsData(PR_FALSE) { +#if defined(MOZ_ENABLE_GTK2) || defined(MOZ_ENABLE_XLIB) + mPixmap = 0; +#endif } nsCairoDrawingSurface::~nsCairoDrawingSurface() { if (mSurface) cairo_surface_destroy (mSurface); - if (mOwnsData && mSurfaceData) - nsMemory::Free(mSurfaceData); + if (mImageSurface && !mFastAccess) // otherwise, mImageSurface == mSurface + cairo_surface_destroy (mImageSurface); + +#if defined(MOZ_ENABLE_GTK2) || defined(MOZ_ENABLE_XLIB) + if (mPixmap != 0) + XFreePixmap(mXDisplay, mPixmap) +#endif } nsresult -nsCairoDrawingSurface::Init(PRUint32 aWidth, PRUint32 aHeight) +nsCairoDrawingSurface::Init(nsCairoDeviceContext *aDC, PRUint32 aWidth, PRUint32 aHeight, PRBool aFastAccess) { NS_ASSERTION(mSurface == nsnull, "Surface already initialized!"); NS_ASSERTION(aWidth > 0 && aHeight > 0, "Invalid surface dimensions!"); - mSurfaceData = (PRUint8*) nsMemory::Alloc(aWidth * aHeight * 4); - - mSurface = cairo_image_surface_create_for_data ((char*) mSurfaceData, CAIRO_FORMAT_ARGB32, - aWidth, aHeight, aWidth * 4); mWidth = aWidth; mHeight = aHeight; - mStride = mWidth * 4; - mDepth = 32; - mOwnsData = PR_TRUE; + + if (aFastAccess) { + mSurface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, aWidth, aHeight); + mDepth = 32; + mFastAccess = PR_TRUE; + } else { + // otherwise, we need to do toolkit-specific stuff +#if defined(MOZ_ENABLE_GTK2) || defined(MOZ_ENABLE_XLIB) + mXDisplay = aDC->GetXDisplay(); + mPixmap = XCreatePixmap(mXDisplay, + aDC->GetXPixmapParentDrawable(), + aWidth, aHeight, 32); + + mSurface = cairo_xlib_surface_create (aDC->GetXDisplay(), + mPixmap, + aDC->GetXVisual(), + CAIRO_FORMAT_ARGB32, + aDC->GetXColormap()); + mDepth = 32; + + mFastAccess = PR_FALSE; +#else +#error write me +#endif + } + + mLockFlags = 0; return NS_OK; } nsresult -nsCairoDrawingSurface::Init (cairo_surface_t *aSurface, PRBool aIsOffscreen, - PRUint32 aWidth, PRUint32 aHeight) +nsCairoDrawingSurface::Init (nsCairoDeviceContext *aDC, nsIWidget *aWidget) { - mSurface = aSurface; - cairo_surface_reference (mSurface); - if (aIsOffscreen) { - char *data; - int width, height, depth, stride; - if (cairo_image_surface_get_data (mSurface, &data, &width, &height, &stride, &depth) == 0) { - mSurfaceData = (PRUint8*) data; - mWidth = width; - mHeight = height; - mStride = stride; - mDepth = depth; - mOwnsData = PR_FALSE; - mIsOffscreen = PR_TRUE; - } else { - NS_WARNING("nsCairoDrawingSurface::Init with non-image offscreen surface"); - } - } else { - mWidth = aWidth; - mHeight = aHeight; - mOwnsData = PR_FALSE; - mIsOffscreen = PR_FALSE; - } + nsNativeWidget nativeWidget = aWidget->GetNativeData(NS_NATIVE_WIDGET); + +#ifdef MOZ_ENABLE_GTK2 + NS_ASSERTION (GDK_IS_WINDOW(aNativeWidget), "unsupported native widget type!"); + mSurface = cairo_xlib_surface_create + (GDK_WINDOW_XDISPLAY(GDK_DRAWABLE(nativeWidget)), + GDK_WINDOW_XWINDOW(GDK_DRAWABLE(nativeWidget)), + GDK_VISUAL_XVISUAL(gdk_drawable_get_visual(GDK_DRAWABLE(nativeWidget))), + CAIRO_FORMAT_ARGB32, // I hope! + GDK_COLORMAP_XCOLORMAP(gdk_drawable_get_colormap(GDK_DRAWABLE(nativeWidget)))); + + Window root_ignore; + int x_ignore, y_ignore, bwidth_ignore; + int width, height, depth; + + XGetGeometry(GDK_WINDOW_XDISPLAY(GDK_DRAWABLE(nativeWidget)), + GDK_WINDOW_XWINDOW(GDK_DRAWABLE(nativeWidget)), + &root_ignore, &x_ignore, &y_ignore, + &width, &height, + &bwidth_ignore, &depth); + + if (depth != 32) + fprintf (stderr, "**** nsCairoDrawingSurface::Init with Widget: depth is %d!\n", depth); + + mWidth = width; + mHeight = height; + mFastAccess = PR_FALSE; + +#else +#error write me +#endif + + mPixmap = 0; + mLockFlags = 0; } NS_IMETHODIMP @@ -108,22 +147,56 @@ nsCairoDrawingSurface::Lock (PRInt32 aX, PRInt32 aY, PRUint32 aWidth, PRUint32 a PRUint32 aFlags) { NS_ASSERTION(aX + aWidth <= mWidth, "Invalid aX/aWidth"); - NS_ASSERTION(aY + aHeight <= mHeight, "Inavlid aY/aHeight"); + NS_ASSERTION(aY + aHeight <= mHeight, "Invalid aY/aHeight"); + NS_ASSERTION(mLockFlags == 0, "nsCairoDrawingSurface::Lock while surface is already locked!"); - if (mIsOffscreen) { - *aBits = mSurfaceData + ((aWidth * 4) * aY) + (aX * 4); - *aStride = mStride; - *aWidthBytes = mWidth * 4; - } else { - NS_WARNING("nsCairoDrawingSurface::Lock with non-offscreen surface!"); + if (!mFastAccess) { + mImageSurface = cairo_surface_get_image (mSurface); } + char *data; + int width, height, stride, depth; + + if (cairo_image_surface_get_data (mImageSurface, + &data, &width, &height, &stride, &depth) + != 0) + { + /* Something went wrong */ + if (!mFastAccess) { + cairo_surface_destroy(mImageSurface); + mImageSurface = nsnull; + } + return NS_ERROR_FAILURE; + } + + *aBits = data + (stride * aY) + (aX * (depth / 8)); + *aStride = stride; + *aWidthBytes = width * (depth / 8); + + mLockFlags = 0; + return NS_OK; } NS_IMETHODIMP nsCairoDrawingSurface::Unlock (void) { + NS_ASSERT(mLockFlags != 0, "nsCairoDrawingSurface::Unlock on non-locked surface!"); + + if (mFastAccess) { + mLockFlags = 0; + return NS_OK; + } + + if (mLockFlags & NS_LOCK_SURFACE_WRITE_ONLY) { + /* need to copy back */ + cairo_surface_set_image (mImageSurface); + } + + cairo_surface_destroy (mImageSurface); + mImageSurface = nsnull; + mLockFlags = 0; + return NS_OK; } @@ -138,14 +211,22 @@ nsCairoDrawingSurface::GetDimensions (PRUint32 *aWidth, PRUint32 *aHeight) NS_IMETHODIMP nsCairoDrawingSurface::IsOffscreen(PRBool *aOffScreen) { - *aOffScreen = mIsOffscreen; + *aOffScreen = PR_FALSE; + + if (mFastAccess) + *aOffScreen = PR_TRUE; +#if defined(MOZ_ENABLE_GTK2) || defined(MOZ_ENABLE_XLIB) + else if (mPixmap) + *aOffScreen = PR_TRUE; +#endif + return NS_OK; } NS_IMETHODIMP nsCairoDrawingSurface::IsPixelAddressable(PRBool *aAddressable) { - *aAddressable = mIsOffscreen; + *aAddressable = mFastAccess; return NS_OK; } diff --git a/gfx/src/cairo/nsCairoDrawingSurface.h b/gfx/src/cairo/nsCairoDrawingSurface.h index be77b84969b8..79b7a01c16c1 100644 --- a/gfx/src/cairo/nsCairoDrawingSurface.h +++ b/gfx/src/cairo/nsCairoDrawingSurface.h @@ -43,21 +43,26 @@ #include +class nsIWidget; +class nsCairoDeviceContext; + class nsCairoDrawingSurface : public nsIDrawingSurface { public: nsCairoDrawingSurface (); virtual ~nsCairoDrawingSurface (); - // create a new image surface - nsresult Init (PRUint32 aWidth, PRUint32 aHeight); - // create a DrawingSurface based on the existing cairo surface - nsresult Init (cairo_surface_t *aSurface, PRBool aIsOffscreen, - PRUint32 aWidth, PRUint32 aHeight); + // create a image surface if aFastAccess == TRUE, otherwise create + // a fast server pixmap + nsresult Init (nsCairoDeviceContext *aDC, PRUint32 aWidth, PRUint32 aHeight, PRBool aFastAccess); + // create a fast drawing surface for a native widget + nsresult Init (nsCairoDevicecontext *aDC, nsIWidget *aWidget); + + // nsISupports interface NS_DECL_ISUPPORTS - //nsIDrawingSurface interface + // nsIDrawingSurface interface NS_IMETHOD Lock(PRInt32 aX, PRInt32 aY, PRUint32 aWidth, PRUint32 aHeight, void **aBits, PRInt32 *aStride, PRInt32 *aWidthBytes, @@ -72,11 +77,16 @@ public: cairo_surface_t *GetCairoSurface(void) { return mSurface; } PRInt32 GetDepth() { return mDepth; } private: - cairo_surface_t *mSurface; - PRUint8 *mSurfaceData; - PRUint32 mWidth, mHeight, mStride, mDepth; - PRBool mOwnsData, mIsOffscreen; + cairo_surface_t *mSurface, *mImageSurface; + +#if defined(MOZ_ENABLE_GTK2) || defined(MOZ_ENABLE_XLIB) + Display *mXDisplay; + Pixmap mPixmap; +#endif + + PRUint32 mLockFlags; + PRBool mFastAccess; + PRUint32 mWidth, mHeight; }; - #endif /* NSCAIRODRAWINGSURFACE__H__ */