Back to index

lightning-sunbird  0.9+nobinonly
nsDrawingSurfaceGTK.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
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 Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * 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  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either of the GNU General Public License Version 2 or later (the "GPL"),
00026  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 
00039 #include <gdk/gdkx.h>
00040 #include <gdk/gdkprivate.h>
00041 #include "nsDrawingSurfaceGTK.h"
00042 
00043 NS_IMPL_ISUPPORTS1(nsDrawingSurfaceGTK, nsIDrawingSurface)
00044 
00045 //#define CHEAP_PERFORMANCE_MEASUREMENT
00046 
00047 #ifdef CHEAP_PERFORMANCE_MEASUREMENT
00048 static PRTime mLockTime, mUnlockTime;
00049 #endif
00050 
00051 #ifdef MOZ_ENABLE_XFT
00052 #include <X11/Xft/Xft.h>
00053 #endif
00054 
00055 nsDrawingSurfaceGTK :: nsDrawingSurfaceGTK()
00056 {
00057   GdkVisual *v;
00058 
00059   mPixmap = nsnull;
00060   mGC = nsnull;
00061   mDepth = 0;
00062   mWidth = 0;
00063   mHeight = 0;
00064   mFlags = 0;
00065 
00066   mImage = nsnull;
00067   mLockWidth = 0;
00068   mLockHeight = 0;
00069   mLockFlags = 0;
00070   mLockX = 0;
00071   mLockY = 0;
00072   mLocked = PR_FALSE;
00073 
00074   v = ::gdk_rgb_get_visual();
00075 
00076   mPixFormat.mRedMask = v->red_mask;
00077   mPixFormat.mGreenMask = v->green_mask;
00078   mPixFormat.mBlueMask = v->blue_mask;
00079   // FIXME
00080   mPixFormat.mAlphaMask = 0;
00081 
00082   mPixFormat.mRedCount = ConvertMaskToCount(v->red_mask);
00083   mPixFormat.mGreenCount = ConvertMaskToCount(v->green_mask);
00084   mPixFormat.mBlueCount = ConvertMaskToCount(v->blue_mask);;
00085 
00086 
00087   mPixFormat.mRedShift = v->red_shift;
00088   mPixFormat.mGreenShift = v->green_shift;
00089   mPixFormat.mBlueShift = v->blue_shift;
00090   // FIXME
00091   mPixFormat.mAlphaShift = 0;
00092 
00093   mDepth = v->depth;
00094 
00095 #ifdef MOZ_ENABLE_XFT
00096   mXftDraw = nsnull;
00097 #endif
00098 }
00099 
00100 nsDrawingSurfaceGTK :: ~nsDrawingSurfaceGTK()
00101 {
00102   if (mPixmap)
00103     ::gdk_pixmap_unref(mPixmap);
00104 
00105   if (mImage)
00106     ::gdk_image_destroy(mImage);
00107 
00108   if (mGC)
00109     gdk_gc_unref(mGC);
00110 
00111 #ifdef MOZ_ENABLE_XFT
00112   if (mXftDraw)
00113     XftDrawDestroy(mXftDraw);
00114 #endif
00115 }
00116 
00134 NS_IMETHODIMP nsDrawingSurfaceGTK :: Lock(PRInt32 aX, PRInt32 aY,
00135                                           PRUint32 aWidth, PRUint32 aHeight,
00136                                           void **aBits, PRInt32 *aStride,
00137                                           PRInt32 *aWidthBytes, PRUint32 aFlags)
00138 {
00139 #ifdef CHEAP_PERFORMANCE_MEASUREMENT
00140   mLockTime = PR_Now();
00141   //  MOZ_TIMER_RESET(mLockTime);
00142   //  MOZ_TIMER_START(mLockTime);
00143 #endif
00144 
00145 #if 0
00146   g_print("nsDrawingSurfaceGTK::Lock() called\n" \
00147           "  aX = %i, aY = %i,\n" \
00148           "  aWidth = %i, aHeight = %i,\n" \
00149           "  aBits, aStride, aWidthBytes,\n" \
00150           "  aFlags = %i\n", aX, aY, aWidth, aHeight, aFlags);
00151 #endif
00152 
00153   if (mLocked)
00154   {
00155     NS_ASSERTION(0, "nested lock attempt");
00156     return NS_ERROR_FAILURE;
00157   }
00158   mLocked = PR_TRUE;
00159 
00160   mLockX = aX;
00161   mLockY = aY;
00162   mLockWidth = aWidth;
00163   mLockHeight = aHeight;
00164   mLockFlags = aFlags;
00165 
00166   // Obtain an ximage from the pixmap.
00167   mImage = ::gdk_image_get(mPixmap, mLockX, mLockY, mLockWidth, mLockHeight);
00168 
00169   if (!mImage) {
00170     mLocked = PR_FALSE;
00171     return NS_ERROR_FAILURE;
00172   }
00173 
00174   *aBits = GDK_IMAGE_XIMAGE(mImage)->data;
00175 
00176   // Use GDK_IMAGE_XIMAGE(mImage)->bits_per_pixel instead of mImage->bpp
00177   // since, although bpp is documented as *bytes* per pixel, GDK1 sometimes
00178   // set it as *bits* per pixel.
00179   *aWidthBytes = aWidth * ((GDK_IMAGE_XIMAGE(mImage)->bits_per_pixel + 7) / 8);
00180   *aStride = GDK_IMAGE_XIMAGE(mImage)->bytes_per_line;
00181 
00182 #ifdef CHEAP_PERFORMANCE_MEASUREMENT
00183   //  MOZ_TIMER_STOP(mLockTime);
00184   //  MOZ_TIMER_LOG(("Time taken to lock: "));
00185   //  MOZ_TIMER_PRINT(mLockTime);
00186   printf("Time taken to lock:   %d\n", PR_Now() - mLockTime);
00187 #endif
00188 
00189   return NS_OK;
00190 }
00191 
00192 NS_IMETHODIMP nsDrawingSurfaceGTK :: Unlock(void)
00193 {
00194 
00195 #ifdef CHEAP_PERFORMANCE_MEASUREMENT
00196   mUnlockTime = PR_Now();
00197 #endif
00198 
00199   //  g_print("nsDrawingSurfaceGTK::UnLock() called\n");
00200   if (!mLocked)
00201   {
00202     NS_ASSERTION(0, "attempting to unlock an DS that isn't locked");
00203     return NS_ERROR_FAILURE;
00204   }
00205 
00206   // If the lock was not read only, put the bits back on the pixmap
00207   if (!(mLockFlags & NS_LOCK_SURFACE_READ_ONLY))
00208   {
00209 #if 0
00210     g_print("%p gdk_draw_image(pixmap=%p,lockx=%d,locky=%d,lockw=%d,lockh=%d)\n",
00211             this,
00212             mPixmap,
00213             mLockX, mLockY,
00214             mLockWidth, mLockHeight);
00215 #endif
00216 
00217     gdk_draw_image(mPixmap,
00218                    mGC,
00219                    mImage,
00220                    0, 0,
00221                    mLockX, mLockY,
00222                    mLockWidth, mLockHeight);
00223   }
00224 
00225   if (mImage)
00226     ::gdk_image_destroy(mImage);
00227   mImage = nsnull;
00228 
00229   mLocked = PR_FALSE;
00230 
00231 
00232 #ifdef CHEAP_PERFORMANCE_MEASUREMENT
00233   printf("Time taken to unlock: %d\n", PR_Now() - mUnlockTime);
00234 #endif
00235 
00236   return NS_OK;
00237 }
00238 
00239 NS_IMETHODIMP nsDrawingSurfaceGTK :: GetDimensions(PRUint32 *aWidth, PRUint32 *aHeight)
00240 {
00241   *aWidth = mWidth;
00242   *aHeight = mHeight;
00243 
00244   return NS_OK;
00245 }
00246 
00247 NS_IMETHODIMP nsDrawingSurfaceGTK :: IsOffscreen(PRBool *aOffScreen)
00248 {
00249   *aOffScreen = mIsOffscreen;
00250   return NS_OK;
00251 }
00252 
00253 NS_IMETHODIMP nsDrawingSurfaceGTK :: IsPixelAddressable(PRBool *aAddressable)
00254 {
00255 // FIXME
00256   *aAddressable = PR_FALSE;
00257   return NS_OK;
00258 }
00259 
00260 NS_IMETHODIMP nsDrawingSurfaceGTK :: GetPixelFormat(nsPixelFormat *aFormat)
00261 {
00262   *aFormat = mPixFormat;
00263 
00264   return NS_OK;
00265 }
00266 
00267 nsresult nsDrawingSurfaceGTK :: Init(GdkDrawable *aDrawable, GdkGC *aGC)
00268 {
00269   if (mGC)
00270     gdk_gc_unref(mGC);
00271 
00272   mGC = gdk_gc_ref(aGC);
00273   mPixmap = aDrawable;
00274 
00275 #ifdef MOZ_WIDGET_GTK
00276   mWidth  = ((GdkWindowPrivate*)aDrawable)->width;
00277   mHeight = ((GdkWindowPrivate*)aDrawable)->height;
00278 #endif /* MOZ_WIDGET_GTK */
00279 
00280 #ifdef MOZ_WIDGET_GTK2
00281   gint width = 0;
00282   gint height = 0;
00283   gdk_drawable_get_size(aDrawable, &width, &height);
00284   mWidth = width;
00285   mHeight = height;
00286 #endif /* MOZ_WIDGET_GTK2 */
00287 
00288   // XXX was i smoking crack when i wrote this comment?
00289   // this is definatly going to be on the screen, as it will be the window of a
00290   // widget or something.
00291   mIsOffscreen = PR_FALSE;
00292 
00293   if (mImage)
00294     gdk_image_destroy(mImage);
00295   mImage = nsnull;
00296 
00297   g_return_val_if_fail(mPixmap != nsnull, NS_ERROR_FAILURE);
00298   
00299   return NS_OK;
00300 }
00301 
00302 nsresult nsDrawingSurfaceGTK :: Init(GdkGC *aGC, PRUint32 aWidth,
00303                                      PRUint32 aHeight, PRUint32 aFlags)
00304 {
00305   //  ::g_return_val_if_fail (aGC != nsnull, NS_ERROR_FAILURE);
00306   //  ::g_return_val_if_fail ((aWidth > 0) && (aHeight > 0), NS_ERROR_FAILURE);
00307   if (mGC)
00308     gdk_gc_unref(mGC);
00309 
00310   mGC = gdk_gc_ref(aGC);
00311   mWidth = aWidth;
00312   mHeight = aHeight;
00313   mFlags = aFlags;
00314 
00315   // we can draw on this offscreen because it has no parent
00316   mIsOffscreen = PR_TRUE;
00317 
00318   mPixmap = ::gdk_pixmap_new(nsnull, mWidth, mHeight, mDepth);
00319 #ifdef MOZ_WIDGET_GTK2
00320   gdk_drawable_set_colormap(GDK_DRAWABLE(mPixmap), gdk_rgb_get_colormap());
00321 #endif
00322 
00323   if (mImage)
00324     gdk_image_destroy(mImage);
00325   mImage = nsnull;
00326 
00327   return mPixmap ? NS_OK : NS_ERROR_FAILURE;
00328 }
00329 
00330 #ifdef MOZ_ENABLE_XFT
00331 XftDraw *nsDrawingSurfaceGTK :: GetXftDraw(void)
00332 {
00333   if (!mXftDraw) {
00334     mXftDraw = XftDrawCreate(GDK_DISPLAY(), GDK_WINDOW_XWINDOW(mPixmap),
00335                              GDK_VISUAL_XVISUAL(::gdk_rgb_get_visual()),
00336                              GDK_COLORMAP_XCOLORMAP(::gdk_rgb_get_cmap()));
00337   }
00338 
00339   return mXftDraw;
00340 }
00341 
00342 void nsDrawingSurfaceGTK :: GetLastXftClip(nsIRegion **aLastRegion)
00343 {
00344   *aLastRegion = mLastXftClip.get();
00345   NS_IF_ADDREF(*aLastRegion);
00346 }
00347 
00348 void nsDrawingSurfaceGTK :: SetLastXftClip(nsIRegion  *aLastRegion)
00349 {
00350   mLastXftClip = aLastRegion;
00351 }
00352 
00353 #endif /* MOZ_ENABLE_XFT */
00354 
00355 /* inline */
00356 PRUint8 
00357 nsDrawingSurfaceGTK::ConvertMaskToCount(unsigned long val)
00358 {
00359   PRUint8 retval = 0;
00360   PRUint8 cur_bit = 0;
00361   // walk through the number, incrementing the value if
00362   // the bit in question is set.
00363   while (cur_bit < (sizeof(unsigned long) * 8)) {
00364     if ((val >> cur_bit) & 0x1) {
00365       retval++;
00366     }
00367     cur_bit++;
00368   }
00369   return retval;
00370 }