Back to index

lightning-sunbird  0.9+nobinonly
nsCairoDrawingSurface.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License
00006  * Version 1.1 (the "License"); you may not use this file except in
00007  * compliance with the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is 
00018  *  Vladimir Vukicevic <vladimir@pobox.com>
00019  * Portions created by the Initial Developer are Copyright (C) 2004
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or
00027  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the NPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the NPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #include "nsCairoDeviceContext.h"
00040 #include "nsCairoDrawingSurface.h"
00041 #include "cairo-xlib.h"
00042 
00043 #if defined(MOZ_ENABLE_GTK2)
00044 #include <sys/ipc.h>
00045 #include <sys/shm.h>
00046 #endif
00047 #ifdef MOZ_ENABLE_XFT
00048 #include <X11/Xft/Xft.h>
00049 #endif
00050 
00051 
00052 #include "nsMemory.h"
00053 
00054 NS_IMPL_ISUPPORTS1(nsCairoDrawingSurface, nsIDrawingSurface)
00055 
00056 nsCairoDrawingSurface::nsCairoDrawingSurface()
00057     : mSurface(nsnull), mImageSurface(nsnull), mDC(nsnull), mNativeWidget(nsnull)
00058 {
00059 #if defined(MOZ_ENABLE_GTK2) || defined(MOZ_ENABLE_XLIB)
00060     mPixmap = 0;
00061     mShmInfo.shmid = -1;
00062 #ifdef MOZ_ENABLE_XFT
00063     mXftDraw = nsnull;
00064 #endif
00065 #endif
00066 }
00067 
00068 nsCairoDrawingSurface::~nsCairoDrawingSurface()
00069 {
00070     fprintf (stderr, "++++ [%p] DESTROY\n", this);
00071 
00072     if (mSurface)
00073         cairo_surface_destroy (mSurface);
00074     if (mImageSurface && !mFastAccess) // otherwise, mImageSurface == mSurface
00075         cairo_surface_destroy (mImageSurface);
00076 
00077 #if defined(MOZ_ENABLE_GTK2) || defined(MOZ_ENABLE_XLIB)
00078     if (mPixmap != 0)
00079         XFreePixmap(mXDisplay, mPixmap);
00080 
00081     if (mShmInfo.shmid != -1 && mShmInfo.shmaddr != 0) {
00082         XShmDetach (mXDisplay, &mShmInfo);
00083         shmdt (mShmInfo.shmaddr);
00084     }
00085 #endif
00086 }
00087 
00088 nsresult
00089 nsCairoDrawingSurface::Init(nsCairoDeviceContext *aDC, PRUint32 aWidth, PRUint32 aHeight, PRBool aFastAccess)
00090 {
00091     NS_ASSERTION(mSurface == nsnull, "Surface already initialized!");
00092     NS_ASSERTION(aWidth > 0 && aHeight > 0, "Invalid surface dimensions!");
00093 
00094     mWidth = aWidth;
00095     mHeight = aHeight;
00096     mDC = aDC;
00097 
00098     if (aFastAccess) {
00099         fprintf (stderr, "++++ [%p] Creating IMAGE surface: %dx%d\n", this, aWidth, aHeight);
00100         mSurface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, aWidth, aHeight);
00101         mFastAccess = PR_TRUE;
00102         mDrawable = nsnull;
00103     } else {
00104         fprintf (stderr, "++++ [%p] Creating PIXMAP surface: %dx%d\n", this, aWidth, aHeight);
00105         // otherwise, we need to do toolkit-specific stuff
00106 #if defined(MOZ_ENABLE_GTK2) || defined(MOZ_ENABLE_XLIB)
00107         mXDisplay = aDC->GetXDisplay();
00108 #if 0
00109         mShmInfo.shmaddr = 0;
00110         mShmInfo.shmid = shmget (IPC_PRIVATE,
00111                                  aWidth * 4 * aHeight,
00112                                  IPC_CREAT | 0600);
00113         if (mShmInfo.shmid != -1) {
00114             mShmInfo.shmaddr = (char*) shmat (mShmInfo.shmid, 0, 0);
00115             mShmInfo.readOnly = False;
00116         }
00117 
00118         if (mShmInfo.shmid != -1 && mShmInfo.shmaddr != 0) {
00119             XShmAttach (mXDisplay, &mShmInfo);
00120             mPixmap = XShmCreatePixmap (mXDisplay, aDC->GetXPixmapParentDrawable(),
00121                                         mShmInfo.shmaddr, &mShmInfo,
00122                                         aWidth, aHeight, DefaultDepth(mXDisplay,DefaultScreen(mXDisplay)));
00123         } else {
00124 #endif
00125             mPixmap = XCreatePixmap(mXDisplay,
00126                                     aDC->GetXPixmapParentDrawable(),
00127                                     aWidth, aHeight, DefaultDepth(mXDisplay,DefaultScreen(mXDisplay)));
00128 #if 0
00129         }
00130 #endif
00131 
00132         mDrawable = (Drawable)mPixmap;
00133 
00134 
00135         // clear the pixmap
00136         XGCValues gcv;
00137         gcv.foreground = WhitePixel(mXDisplay,DefaultScreen(mXDisplay));
00138         gcv.background = 0;
00139         GC gc = XCreateGC (mXDisplay, mPixmap, GCForeground | GCBackground, &gcv);
00140         XFillRectangle (mXDisplay, mPixmap, gc, 0, 0, aWidth, aHeight);
00141         XFreeGC (mXDisplay, gc);
00142 
00143         // create the surface
00144         mSurface = cairo_xlib_surface_create (mXDisplay,
00145                                               mPixmap,
00146                                               aDC->GetXVisual(),
00147                                               CAIRO_FORMAT_ARGB32,
00148                                               aDC->GetXColormap());
00149 
00150         mFastAccess = PR_FALSE;
00151 #else
00152 #error write me
00153 #endif
00154     }
00155 
00156     mLockFlags = 0;
00157 
00158     return NS_OK;
00159 }
00160 
00161 nsresult
00162 nsCairoDrawingSurface::Init (nsCairoDeviceContext *aDC, nsIWidget *aWidget)
00163 {
00164     nsNativeWidget nativeWidget = aWidget->GetNativeData(NS_NATIVE_WIDGET);
00165     return Init (aDC, nativeWidget);
00166 }
00167 
00168 nsresult
00169 nsCairoDrawingSurface::Init (nsCairoDeviceContext *aDC, nsNativeWidget aNativeWidget)
00170 {
00171     fprintf (stderr, "++++ [%p] Creating DRAWABLE (0x%08x) surface\n", this, aNativeWidget);
00172 
00173     mDC = aDC;
00174 
00175 #ifdef MOZ_ENABLE_GTK2
00176     mNativeWidget = aNativeWidget;
00177     mDrawable = GDK_DRAWABLE_XID(GDK_DRAWABLE(aNativeWidget));
00178     NS_ASSERTION (GDK_IS_WINDOW(aNativeWidget), "unsupported native widget type!");
00179     mSurface = cairo_xlib_surface_create
00180         (GDK_WINDOW_XDISPLAY(GDK_DRAWABLE(aNativeWidget)),
00181          GDK_WINDOW_XWINDOW(GDK_DRAWABLE(aNativeWidget)),
00182          GDK_VISUAL_XVISUAL(gdk_drawable_get_visual(GDK_DRAWABLE(aNativeWidget))),
00183          CAIRO_FORMAT_ARGB32, // I hope!
00184          GDK_COLORMAP_XCOLORMAP(gdk_drawable_get_colormap(GDK_DRAWABLE(aNativeWidget))));
00185 
00186     Window root_ignore;
00187     int x_ignore, y_ignore;
00188     unsigned int bwidth_ignore, width, height, depth;
00189 
00190     XGetGeometry(GDK_WINDOW_XDISPLAY(GDK_DRAWABLE(aNativeWidget)),
00191                  GDK_WINDOW_XWINDOW(GDK_DRAWABLE(aNativeWidget)),
00192                  &root_ignore, &x_ignore, &y_ignore,
00193                  &width, &height,
00194                  &bwidth_ignore, &depth);
00195 
00196 #if 0
00197     if (depth != 32)
00198         fprintf (stderr, "**** nsCairoDrawingSurface::Init with Widget: depth is %d!\n", depth);
00199 #endif
00200 
00201     mWidth = width;
00202     mHeight = height;
00203     mFastAccess = PR_FALSE;
00204 
00205 #else
00206 #error write me
00207 #endif
00208 
00209     mPixmap = 0;
00210     mLockFlags = 0;
00211 
00212     return NS_OK;
00213 }
00214 
00215 NS_IMETHODIMP
00216 nsCairoDrawingSurface::Lock (PRInt32 aX, PRInt32 aY, PRUint32 aWidth, PRUint32 aHeight,
00217                              void **aBits, PRInt32 *aStride, PRInt32 *aWidthBytes,
00218                              PRUint32 aFlags)
00219 {
00220     NS_ASSERTION(aX + aWidth <= mWidth, "Invalid aX/aWidth");
00221     NS_ASSERTION(aY + aHeight <= mHeight, "Invalid aY/aHeight");
00222     NS_ASSERTION(mLockFlags == 0, "nsCairoDrawingSurface::Lock while surface is already locked!");
00223 
00224 #if 0
00225     if (!mFastAccess) {
00226         mImageSurface = cairo_surface_get_image (mSurface);
00227     }
00228 
00229     char *data;
00230     int width, height, stride, depth;
00231 
00232     if (cairo_image_surface_get_data (mImageSurface,
00233                                       &data, &width, &height, &stride, &depth)
00234         != 0)
00235     {
00236         /* Something went wrong */
00237         if (!mFastAccess) {
00238             cairo_surface_destroy(mImageSurface);
00239             mImageSurface = nsnull;
00240         }
00241         return NS_ERROR_FAILURE;
00242     }
00243     *aBits = data + (stride * aY) + (aX * (depth / 8));
00244     *aStride = stride;
00245     *aWidthBytes = width * (depth / 8);
00246 
00247     mLockFlags = 0;
00248 
00249 #endif
00250     return NS_OK;
00251 }
00252 
00253 NS_IMETHODIMP
00254 nsCairoDrawingSurface::Unlock (void)
00255 {
00256     NS_ASSERTION(mLockFlags != 0, "nsCairoDrawingSurface::Unlock on non-locked surface!");
00257 
00258     if (mFastAccess) {
00259         mLockFlags = 0;
00260         return NS_OK;
00261     }
00262 
00263     if (mLockFlags & NS_LOCK_SURFACE_WRITE_ONLY) {
00264         /* need to copy back */
00265         //cairo_surface_set_image (mSurface, mImageSurface);
00266     }
00267 
00268     cairo_surface_destroy (mImageSurface);
00269     mImageSurface = nsnull;
00270     mLockFlags = 0;
00271 
00272     return NS_OK;
00273 }
00274 
00275 NS_IMETHODIMP
00276 nsCairoDrawingSurface::GetDimensions (PRUint32 *aWidth, PRUint32 *aHeight)
00277 {
00278     *aWidth = mWidth;
00279     *aHeight = mHeight;
00280     return NS_OK;
00281 }
00282 
00283 NS_IMETHODIMP
00284 nsCairoDrawingSurface::IsOffscreen(PRBool *aOffScreen)
00285 {
00286     *aOffScreen = PR_FALSE;
00287 
00288     if (mFastAccess)
00289         *aOffScreen = PR_TRUE;
00290 #if defined(MOZ_ENABLE_GTK2) || defined(MOZ_ENABLE_XLIB)
00291     else if (mPixmap)
00292         *aOffScreen = PR_TRUE;
00293 #endif
00294 
00295     return NS_OK;
00296 }
00297 
00298 NS_IMETHODIMP
00299 nsCairoDrawingSurface::IsPixelAddressable(PRBool *aAddressable)
00300 {
00301     *aAddressable = mFastAccess;
00302     return NS_OK;
00303 }
00304 
00305 NS_IMETHODIMP
00306 nsCairoDrawingSurface::GetPixelFormat(nsPixelFormat *aFormat)
00307 {
00308     aFormat->mRedMask = 0x000000ff;
00309     aFormat->mGreenMask = 0x0000ff00;
00310     aFormat->mBlueMask = 0x00ff0000;
00311     aFormat->mAlphaMask = 0xff000000;
00312 
00313     aFormat->mRedCount = 8;
00314     aFormat->mGreenCount = 8;
00315     aFormat->mBlueCount = 8;
00316     aFormat->mAlphaCount = 8;
00317 
00318     aFormat->mRedShift = 0;
00319     aFormat->mGreenShift = 8;
00320     aFormat->mBlueShift = 16;
00321     aFormat->mAlphaCount = 24;
00322 
00323     return NS_OK;
00324 }
00325 
00326 #ifdef MOZ_ENABLE_XFT
00327 XftDraw *
00328 nsCairoDrawingSurface::GetXftDraw(void)
00329 {
00330     if (mDrawable == nsnull) {
00331         NS_ERROR("GetXftDraw with null drawable!\n");
00332     }
00333 
00334     if (!mXftDraw) {
00335         fprintf (stderr, "++++ [%p] Creating XFTDRAW for (0x%08x)\n", this, mDrawable);
00336 
00337         mXftDraw = XftDrawCreate(mDC->GetXDisplay(), mDrawable,
00338                                  mDC->GetXVisual(),
00339                                  mDC->GetXColormap());
00340     }
00341 
00342     return mXftDraw;
00343 }
00344 
00345 void
00346 nsCairoDrawingSurface::GetLastXftClip(nsIRegion **aLastRegion)
00347 {
00348     *aLastRegion = mLastXftClip.get();
00349     NS_IF_ADDREF(*aLastRegion);
00350 }
00351 
00352 void
00353 nsCairoDrawingSurface::SetLastXftClip(nsIRegion *aLastRegion)
00354 {
00355     mLastXftClip = aLastRegion;
00356 }
00357 
00358 #endif /* MOZ_ENABLE_XFT */