Back to index

lightning-sunbird  0.9+nobinonly
nsRenderingContextGTK.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  *   Tomi Leppikangas <tomi.leppikangas@oulu.fi>
00024  *   Roland Mainz <roland.mainz@informatik.med.uni-giessen.de>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either of the GNU General Public License Version 2 or later (the "GPL"),
00028  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 #include "nsFixedSizeAllocator.h"
00041 #include "nsRenderingContextGTK.h"
00042 #include "nsRegionGTK.h"
00043 #include "nsImageGTK.h"
00044 #include "nsGraphicsStateGTK.h"
00045 #include "nsCompressedCharMap.h"
00046 #include <math.h>
00047 #include "nsGCCache.h"
00048 #include <gtk/gtk.h>
00049 #include <gdk/gdkx.h>
00050 #include "prmem.h"
00051 #include "prenv.h"
00052 
00053 #include "nsIFontMetricsGTK.h"
00054 #include "nsDeviceContextGTK.h"
00055 #include "nsFontMetricsUtils.h"
00056 
00057 #ifdef MOZ_WIDGET_GTK2
00058 #include <gdk/gdkwindow.h>
00059 #endif
00060 
00061 NS_IMPL_ISUPPORTS1(nsRenderingContextGTK, nsIRenderingContext)
00062 
00063 #define NSRECT_TO_GDKRECT(ns,gdk) \
00064   PR_BEGIN_MACRO \
00065   gdk.x = ns.x; \
00066   gdk.y = ns.y; \
00067   gdk.width = ns.width; \
00068   gdk.height = ns.height; \
00069   PR_END_MACRO
00070 
00071 static nsGCCache *gcCache = nsnull;
00072 static nsFixedSizeAllocator *gStatePool = nsnull;
00073 
00074 nsRenderingContextGTK::nsRenderingContextGTK()
00075 {
00076   mFontMetrics = nsnull;
00077   mContext = nsnull;
00078   mSurface = nsnull;
00079   mOffscreenSurface = nsnull;
00080   mCurrentColor = NS_RGB(255, 255, 255);  // set it to white
00081   mCurrentLineStyle = nsLineStyle_kSolid;
00082   mTranMatrix = nsnull;
00083   mP2T = 1.0f;
00084   mClipRegion = nsnull;
00085   mDrawStringBuf = nsnull;
00086   mGC = nsnull;
00087 
00088   mFunction = GDK_COPY;
00089 
00090   PushState();
00091 }
00092 
00093 nsRenderingContextGTK::~nsRenderingContextGTK()
00094 {
00095   // Destroy the State Machine
00096   PRInt32 cnt = mStateCache.Count();
00097 
00098   while (--cnt >= 0)
00099     PopState();
00100 
00101   if (mTranMatrix) {
00102     if (gStatePool) {
00103       mTranMatrix->~nsTransform2D();
00104       gStatePool->Free(mTranMatrix, sizeof(nsTransform2D));
00105     } else {
00106       delete mTranMatrix;
00107     }
00108   }
00109   NS_IF_RELEASE(mOffscreenSurface);
00110   NS_IF_RELEASE(mFontMetrics);
00111   NS_IF_RELEASE(mContext);
00112 
00113   if (nsnull != mDrawStringBuf) {
00114     delete [] mDrawStringBuf;
00115   }
00116 
00117   if (nsnull != mGC) {
00118     gdk_gc_unref(mGC);
00119   }
00120 }
00121 
00122 /*static*/ nsresult
00123 nsRenderingContextGTK::Shutdown()
00124 {
00125   delete gcCache;
00126   delete gStatePool;
00127   return NS_OK;
00128 }
00129 
00130 NS_IMETHODIMP nsRenderingContextGTK::Init(nsIDeviceContext* aContext,
00131                                           nsIWidget *aWindow)
00132 {
00133   mContext = aContext;
00134   NS_IF_ADDREF(mContext);
00135 
00136 //  ::gdk_rgb_init();
00137 
00138   mSurface = new nsDrawingSurfaceGTK();
00139 
00140   if (mSurface)
00141   {
00142     if (!aWindow) return NS_ERROR_NULL_POINTER;
00143 
00144     // we want to ref the window here so that we can unref in the drawing surface.
00145     // otherwise, we can not unref and that causes windows that are created in the
00146     // drawing surface not to be freed.
00147     GdkDrawable *win = (GdkDrawable*)aWindow->GetNativeData(NS_NATIVE_WINDOW);
00148     if (win)
00149       gdk_window_ref((GdkWindow*)win);
00150     else
00151     {
00152       GtkWidget *w = (GtkWidget *) aWindow->GetNativeData(NS_NATIVE_WIDGET);
00153 
00154       if (!w)
00155       {
00156           delete mSurface;
00157           mSurface = nsnull;
00158           return NS_ERROR_NULL_POINTER;
00159       }
00160 
00161       win = gdk_pixmap_new(nsnull,
00162                            w->allocation.width,
00163                            w->allocation.height,
00164                            gdk_rgb_get_visual()->depth);
00165 #ifdef MOZ_WIDGET_GTK2
00166       gdk_drawable_set_colormap(win, gdk_rgb_get_colormap());
00167 #endif
00168     }
00169 
00170     GdkGC *gc = (GdkGC *)aWindow->GetNativeData(NS_NATIVE_GRAPHIC);
00171     mSurface->Init(win,gc);
00172 
00173     mOffscreenSurface = mSurface;
00174 
00175     NS_ADDREF(mSurface);
00176 
00177     // aWindow->GetNativeData() ref'd the gc.
00178     // only Win32 has a FreeNativeData() method.
00179     // so do this manually here.
00180     gdk_gc_unref(gc);
00181   }
00182   return (CommonInit());
00183 }
00184 
00185 NS_IMETHODIMP nsRenderingContextGTK::Init(nsIDeviceContext* aContext,
00186                                           nsIDrawingSurface* aSurface)
00187 {
00188   mContext = aContext;
00189   NS_IF_ADDREF(mContext);
00190 
00191   mSurface = (nsDrawingSurfaceGTK *) aSurface;
00192   NS_ADDREF(mSurface);
00193   mOffscreenSurface = mSurface;
00194 
00195   return (CommonInit());
00196 }
00197 
00198 NS_IMETHODIMP nsRenderingContextGTK::CommonInit()
00199 {
00200   mP2T = mContext->DevUnitsToAppUnits();
00201   float app2dev;
00202   app2dev = mContext->AppUnitsToDevUnits();
00203   mTranMatrix->AddScale(app2dev, app2dev);
00204 
00205   return NS_OK;
00206 }
00207 
00208 NS_IMETHODIMP nsRenderingContextGTK::GetHints(PRUint32& aResult)
00209 {
00210   PRUint32 result = 0;
00211 
00212   // Most X servers implement 8 bit text rendering alot faster than
00213   // XChar2b rendering. In addition, we can avoid the PRUnichar to
00214   // XChar2b conversion. So we set this bit...
00215   result |= NS_RENDERING_HINT_FAST_8BIT_TEXT;
00216 
00217   // XXX see if we are rendering to the local display or to a remote
00218   // dispaly and set the NS_RENDERING_HINT_REMOTE_RENDERING accordingly
00219 
00220   // see if the font metrics has anything more to offer
00221   result |= NS_FontMetricsGetHints();
00222 
00223   aResult = result;
00224   return NS_OK;
00225 }
00226 
00227 NS_IMETHODIMP nsRenderingContextGTK::LockDrawingSurface(PRInt32 aX, PRInt32 aY,
00228                                                           PRUint32 aWidth, PRUint32 aHeight,
00229                                                           void **aBits, PRInt32 *aStride,
00230                                                           PRInt32 *aWidthBytes, PRUint32 aFlags)
00231 {
00232   PushState();
00233 
00234   return mSurface->Lock(aX, aY, aWidth, aHeight,
00235                         aBits, aStride, aWidthBytes, aFlags);
00236 }
00237 
00238 NS_IMETHODIMP nsRenderingContextGTK::UnlockDrawingSurface(void)
00239 {
00240   PopState();
00241 
00242   mSurface->Unlock();
00243   
00244   return NS_OK;
00245 }
00246 
00247 NS_IMETHODIMP nsRenderingContextGTK::SelectOffScreenDrawingSurface(nsIDrawingSurface* aSurface)
00248 {
00249   if (nsnull == aSurface)
00250     mSurface = mOffscreenSurface;
00251   else
00252     mSurface = (nsDrawingSurfaceGTK *)aSurface;
00253 
00254   return NS_OK;
00255 }
00256 
00257 NS_IMETHODIMP nsRenderingContextGTK::GetDrawingSurface(nsIDrawingSurface* *aSurface)
00258 {
00259   *aSurface = mSurface;
00260   return NS_OK;
00261 }
00262 
00263 NS_IMETHODIMP nsRenderingContextGTK::Reset()
00264 {
00265 #ifdef DEBUG
00266   g_print("nsRenderingContextGTK::Reset() called\n");
00267 #endif
00268   return NS_OK;
00269 }
00270 
00271 NS_IMETHODIMP nsRenderingContextGTK::GetDeviceContext(nsIDeviceContext *&aContext)
00272 {
00273   NS_IF_ADDREF(mContext);
00274   aContext = mContext;
00275   return NS_OK;
00276 }
00277 #if 0
00278 NS_IMETHODIMP nsRenderingContextGTK::PushState(PRInt32 aFlags)
00279 {
00280   //  Get a new GS
00281 #ifdef USE_GS_POOL
00282   nsGraphicsState *state = nsGraphicsStatePool::GetNewGS();
00283 #else
00284   nsGraphicsState *state = new nsGraphicsState;
00285 #endif
00286   // Push into this state object, add to vector
00287   if (!state)
00288     return NS_ERROR_FAILURE;
00289 
00290   if (aFlags & NS_STATE_COLOR) {
00291     state->mColor = mCurrentColor;
00292   }
00293 
00294   if (aFlags & NS_STATE_TRANSFORM) {
00295     state->mMatrix = mTranMatrix;
00296     if (nsnull == mTranMatrix) {
00297       mTranMatrix = new nsTransform2D();
00298     } else {
00299       mTranMatrix = new nsTransform2D(mTranMatrix);
00300     }
00301   }
00302 
00303   if (aFlags & NS_STATE_FONT) {
00304     NS_IF_ADDREF(mFontMetrics);
00305     state->mFontMetrics = mFontMetrics;
00306   }
00307 
00308   if (aFlags & NS_STATE_CLIP) {
00309     state->mClipRegion = mClipRegion;
00310   }
00311 
00312   if (aFlags & NS_STATE_LINESTYLE) {
00313     state->mLineStyle = mCurrentLineStyle;
00314   }
00315 
00316   mStateCache.AppendElement(state);
00317   
00318   return NS_OK;
00319 }
00320 #endif
00321 
00322 NS_IMETHODIMP nsRenderingContextGTK::PushState(void)
00323 {
00324   //  Get a new GS
00325   if (!gStatePool) {
00326     gStatePool = new nsFixedSizeAllocator();
00327     size_t sizes[] = {sizeof(nsGraphicsState), sizeof(nsTransform2D)};
00328     if (gStatePool)
00329       gStatePool->Init("GTKStatePool", sizes, sizeof(sizes)/sizeof(size_t),
00330                        sizeof(nsGraphicsState)*64);
00331   }
00332 
00333   nsGraphicsState *state = nsnull;
00334   if (gStatePool) {
00335     void *space = gStatePool->Alloc(sizeof(nsGraphicsState));
00336     if (space)
00337       state = ::new(space) nsGraphicsState;
00338   } else {
00339     state = new nsGraphicsState;
00340   }
00341 
00342   // Push into this state object, add to vector
00343   if (!state)
00344     return NS_ERROR_FAILURE;
00345 
00346   state->mMatrix = mTranMatrix;
00347 
00348   if (gStatePool) {
00349     void *space = gStatePool->Alloc(sizeof(nsTransform2D));
00350     if (mTranMatrix)
00351       mTranMatrix = ::new(space) nsTransform2D(mTranMatrix);
00352     else
00353       mTranMatrix = ::new(space) nsTransform2D();
00354   } else {
00355     if (mTranMatrix)
00356       mTranMatrix = ::new nsTransform2D(mTranMatrix);
00357     else
00358       mTranMatrix = ::new nsTransform2D();
00359   }
00360 
00361   // set state to mClipRegion.. SetClip{Rect,Region}() will do copy-on-write stuff
00362   state->mClipRegion = mClipRegion;
00363 
00364   NS_IF_ADDREF(mFontMetrics);
00365   state->mFontMetrics = mFontMetrics;
00366 
00367   state->mColor = mCurrentColor;
00368   state->mLineStyle = mCurrentLineStyle;
00369 
00370   mStateCache.AppendElement(state);
00371   
00372   return NS_OK;
00373 }
00374 
00375 NS_IMETHODIMP nsRenderingContextGTK::PopState(void)
00376 {
00377   PRUint32 cnt = mStateCache.Count();
00378   nsGraphicsState * state;
00379 
00380   if (cnt > 0) {
00381     state = (nsGraphicsState *)mStateCache.ElementAt(cnt - 1);
00382     mStateCache.RemoveElementAt(cnt - 1);
00383 
00384     // Assign all local attributes from the state object just popped
00385     if (state->mMatrix) {
00386       if (mTranMatrix) {
00387         if (gStatePool) {
00388           mTranMatrix->~nsTransform2D();
00389           gStatePool->Free(mTranMatrix, sizeof(nsTransform2D));
00390         } else {
00391           delete mTranMatrix;
00392         }
00393       }
00394       mTranMatrix = state->mMatrix;
00395     }
00396 
00397     mClipRegion.swap(state->mClipRegion);
00398 
00399     if (state->mFontMetrics && (mFontMetrics != state->mFontMetrics))
00400       SetFont(state->mFontMetrics);
00401 
00402     if (state->mColor != mCurrentColor)
00403       SetColor(state->mColor);    
00404 
00405     if (state->mLineStyle != mCurrentLineStyle)
00406       SetLineStyle(state->mLineStyle);
00407 
00408     // Delete this graphics state object
00409     if (gStatePool) {
00410       state->~nsGraphicsState();
00411       gStatePool->Free(state, sizeof(nsGraphicsState));
00412     } else {
00413       delete state;
00414     }
00415   }
00416 
00417   return NS_OK;
00418 }
00419 
00420 NS_IMETHODIMP nsRenderingContextGTK::IsVisibleRect(const nsRect& aRect,
00421                                                    PRBool &aVisible)
00422 {
00423   aVisible = PR_TRUE;
00424   return NS_OK;
00425 }
00426 
00427 NS_IMETHODIMP nsRenderingContextGTK::GetClipRect(nsRect &aRect, PRBool &aClipValid)
00428 {
00429   PRInt32 x, y, w, h;
00430   
00431   if (!mClipRegion)
00432     return NS_ERROR_FAILURE;
00433 
00434   if (!mClipRegion->IsEmpty()) {
00435     mClipRegion->GetBoundingBox(&x,&y,&w,&h);
00436     aRect.SetRect(x,y,w,h);
00437     aClipValid = PR_TRUE;
00438   } else {
00439     aRect.SetRect(0,0,0,0);
00440     aClipValid = PR_FALSE;
00441   }
00442 
00443   return NS_OK;
00444 }
00445 
00446 #ifdef DEBUG
00447 // #define TRACE_SET_CLIP
00448 #endif
00449 
00450 #ifdef TRACE_SET_CLIP
00451 static char *
00452 nsClipCombine_to_string(nsClipCombine aCombine)
00453 {
00454   switch(aCombine)
00455     {
00456       case nsClipCombine_kIntersect:
00457         return "nsClipCombine_kIntersect";
00458         break;
00459 
00460       case nsClipCombine_kUnion:
00461         return "nsClipCombine_kUnion";
00462         break;
00463 
00464       case nsClipCombine_kSubtract:
00465         return "nsClipCombine_kSubtract";
00466         break;
00467 
00468       case nsClipCombine_kReplace:
00469         return "nsClipCombine_kReplace";
00470         break;
00471     }
00472 
00473   return "something got screwed";
00474 }
00475 #endif // TRACE_SET_CLIP
00476 
00477 void
00478 nsRenderingContextGTK::CreateClipRegion()
00479 {
00480   // We have 3 cases to deal with:
00481   //  1 - There is no mClipRegion -> Create one
00482   //  2 - There is an mClipRegion shared w/ stack -> Duplicate and unshare
00483   //  3 - There is an mClipRegion and its not shared -> return
00484 
00485   if (mClipRegion) {
00486     PRUint32 cnt = mStateCache.Count();
00487 
00488     if (cnt > 0) {
00489       nsGraphicsState *state;
00490       state = (nsGraphicsState *)mStateCache.ElementAt(cnt - 1);
00491 
00492       if (state->mClipRegion == mClipRegion) {
00493         mClipRegion = new nsRegionGTK;
00494         if (mClipRegion) {
00495           mClipRegion->SetTo(*state->mClipRegion);
00496         }
00497       }
00498     }
00499   } else {
00500 
00501     PRUint32 w, h;
00502     mSurface->GetSize(&w, &h);
00503 
00504     mClipRegion = new nsRegionGTK;
00505     if (mClipRegion) {
00506       mClipRegion->Init();
00507       mClipRegion->SetTo(0, 0, w, h);
00508     }
00509   }
00510 }
00511 
00512 NS_IMETHODIMP nsRenderingContextGTK::SetClipRect(const nsRect& aRect,
00513                                                  nsClipCombine aCombine)
00514 {
00515   nsRect trect = aRect;
00516   mTranMatrix->TransformCoord(&trect.x, &trect.y,
00517                               &trect.width, &trect.height);
00518   SetClipRectInPixels(trect, aCombine);
00519   return NS_OK;
00520 }
00521 
00522 void nsRenderingContextGTK::SetClipRectInPixels(const nsRect& aRect,
00523                                                 nsClipCombine aCombine)
00524 {
00525   CreateClipRegion();
00526 
00527 #ifdef TRACE_SET_CLIP
00528   printf("nsRenderingContextGTK::SetClipRect(%s)\n",
00529          nsClipCombine_to_string(aCombine));
00530 #endif // TRACE_SET_CLIP
00531 
00532   switch(aCombine)
00533   {
00534     case nsClipCombine_kIntersect:
00535       mClipRegion->Intersect(aRect.x,aRect.y,aRect.width,aRect.height);
00536       break;
00537     case nsClipCombine_kUnion:
00538       mClipRegion->Union(aRect.x,aRect.y,aRect.width,aRect.height);
00539       break;
00540     case nsClipCombine_kSubtract:
00541       mClipRegion->Subtract(aRect.x,aRect.y,aRect.width,aRect.height);
00542       break;
00543     case nsClipCombine_kReplace:
00544       mClipRegion->SetTo(aRect.x,aRect.y,aRect.width,aRect.height);
00545       break;
00546   }
00547 #if 0
00548   nscolor color = mCurrentColor;
00549   SetColor(NS_RGB(255,   0,   0));
00550   FillRect(aRect);
00551   SetColor(color);
00552 #endif
00553 }
00554 
00555 void nsRenderingContextGTK::UpdateGC()
00556 {
00557   GdkGCValues values;
00558   GdkGCValuesMask valuesMask;
00559 
00560   if (mGC)
00561     gdk_gc_unref(mGC);
00562 
00563   memset(&values, 0, sizeof(GdkGCValues));
00564 
00565   values.foreground.pixel =
00566     gdk_rgb_xpixel_from_rgb(NS_TO_GDK_RGB(mCurrentColor));
00567   values.foreground.red = (NS_GET_R(mCurrentColor) << 8) | NS_GET_R(mCurrentColor);
00568   values.foreground.green = (NS_GET_G(mCurrentColor) << 8) | NS_GET_G(mCurrentColor);
00569   values.foreground.blue = (NS_GET_B(mCurrentColor) << 8) | NS_GET_B(mCurrentColor);
00570   valuesMask = GDK_GC_FOREGROUND;
00571 
00572 #ifdef MOZ_ENABLE_COREXFONTS
00573   if (mFontMetrics) {
00574     GdkFont *font = mFontMetrics->GetCurrentGDKFont();
00575     if (font) {
00576       valuesMask = GdkGCValuesMask(valuesMask | GDK_GC_FONT);
00577       values.font = font;
00578     }
00579   }
00580 #endif
00581 
00582   valuesMask = GdkGCValuesMask(valuesMask | GDK_GC_LINE_STYLE);
00583   values.line_style = mLineStyle;
00584 
00585   valuesMask = GdkGCValuesMask(valuesMask | GDK_GC_FUNCTION);
00586   values.function = mFunction;
00587 
00588   GdkRegion *rgn = nsnull;
00589   if (mClipRegion) {
00590     mClipRegion->GetNativeRegion((void*&)rgn);
00591   }
00592 
00593   if (!gcCache) {
00594     gcCache = new nsGCCache();
00595     if (!gcCache) return;
00596   }
00597 
00598   mGC = gcCache->GetGC(mOffscreenSurface->GetDrawable(),
00599                        &values,
00600                        valuesMask,
00601                        rgn);
00602 
00603   if (mDashes)
00604     ::XSetDashes(GDK_DISPLAY(), GDK_GC_XGC(mGC),
00605                  0, mDashList, mDashes);
00606 }
00607 
00608 NS_IMETHODIMP nsRenderingContextGTK::SetClipRegion(const nsIRegion& aRegion,
00609                                                    nsClipCombine aCombine)
00610 {
00611   CreateClipRegion();
00612 
00613   switch(aCombine)
00614   {
00615     case nsClipCombine_kIntersect:
00616       mClipRegion->Intersect(aRegion);
00617       break;
00618     case nsClipCombine_kUnion:
00619       mClipRegion->Union(aRegion);
00620       break;
00621     case nsClipCombine_kSubtract:
00622       mClipRegion->Subtract(aRegion);
00623       break;
00624     case nsClipCombine_kReplace:
00625       mClipRegion->SetTo(aRegion);
00626       break;
00627   }
00628 
00629   return NS_OK;
00630 }
00631 
00635 NS_IMETHODIMP nsRenderingContextGTK::CopyClipRegion(nsIRegion &aRegion)
00636 {
00637   if (!mClipRegion)
00638     return NS_ERROR_FAILURE;
00639 
00640   aRegion.SetTo(*mClipRegion);
00641   return NS_OK;
00642 }
00643 
00644 NS_IMETHODIMP nsRenderingContextGTK::GetClipRegion(nsIRegion **aRegion)
00645 {
00646   nsresult rv = NS_ERROR_FAILURE;
00647 
00648   if (!aRegion || !mClipRegion)
00649     return NS_ERROR_NULL_POINTER;
00650 
00651   if (mClipRegion) {
00652     if (*aRegion) { // copy it, they should be using CopyClipRegion 
00653       (*aRegion)->SetTo(*mClipRegion);
00654       rv = NS_OK;
00655     } else {
00656       nsCOMPtr<nsIRegion> newRegion = new nsRegionGTK;
00657       if (newRegion) {
00658         newRegion->Init();
00659         newRegion->SetTo(*mClipRegion);
00660         NS_ADDREF(*aRegion = newRegion);
00661       }
00662     }
00663   } else {
00664 #ifdef DEBUG
00665     printf("null clip region, can't make a valid copy\n");
00666 #endif
00667     rv = NS_ERROR_FAILURE;
00668   }
00669 
00670   return rv;
00671 }
00672 
00673 NS_IMETHODIMP nsRenderingContextGTK::SetColor(nscolor aColor)
00674 {
00675   if (nsnull == mContext)  
00676     return NS_ERROR_FAILURE;
00677 
00678   mCurrentColor = aColor;
00679 
00680   return NS_OK;
00681 }
00682 
00683 NS_IMETHODIMP nsRenderingContextGTK::GetColor(nscolor &aColor) const
00684 {
00685   aColor = mCurrentColor;
00686   return NS_OK;
00687 }
00688 
00689 NS_IMETHODIMP nsRenderingContextGTK::SetFont(const nsFont& aFont, nsIAtom* aLangGroup)
00690 {
00691   nsCOMPtr<nsIFontMetrics> newMetrics;
00692   nsresult rv = mContext->GetMetricsFor(aFont, aLangGroup, *getter_AddRefs(newMetrics));
00693   if (NS_SUCCEEDED(rv)) {
00694     rv = SetFont(newMetrics);
00695   }
00696   return rv;
00697 }
00698 
00699 NS_IMETHODIMP nsRenderingContextGTK::SetFont(nsIFontMetrics *aFontMetrics)
00700 {
00701   NS_IF_RELEASE(mFontMetrics);
00702   mFontMetrics = NS_REINTERPRET_CAST(nsIFontMetricsGTK *, aFontMetrics);
00703   NS_IF_ADDREF(mFontMetrics);
00704 
00705   return NS_OK;
00706 }
00707 
00708 NS_IMETHODIMP nsRenderingContextGTK::SetLineStyle(nsLineStyle aLineStyle)
00709 {
00710   if (aLineStyle != mCurrentLineStyle)
00711   {
00712     switch(aLineStyle)
00713     { 
00714       case nsLineStyle_kSolid:
00715         {
00716           mLineStyle = GDK_LINE_SOLID;
00717           mDashes = 0;
00718           /*          ::gdk_gc_set_line_attributes(mSurface->GetGC(),
00719                                        1,
00720                                        GDK_LINE_SOLID,
00721                                        (GdkCapStyle)0,
00722                                        (GdkJoinStyle)0);
00723           */
00724         }
00725         break;
00726 
00727       case nsLineStyle_kDashed:
00728         {
00729           mLineStyle = GDK_LINE_ON_OFF_DASH;
00730           mDashList[0] = mDashList[1] = 4;
00731           mDashes = 2;
00732 
00733           /*          ::gdk_gc_set_dashes(mSurface->GetGC(), 
00734                       0, dashed, 2);
00735           */
00736         }
00737         break;
00738 
00739       case nsLineStyle_kDotted:
00740         {
00741           mDashList[0] = mDashList[1] = 1;
00742           mLineStyle = GDK_LINE_ON_OFF_DASH;
00743           mDashes = 2;
00744 
00745           /*          ::gdk_gc_set_dashes(mSurface->GetGC(), 
00746                       0, dotted, 2);
00747           */
00748         }
00749         break;
00750 
00751     default:
00752         break;
00753 
00754     }
00755     
00756     mCurrentLineStyle = aLineStyle ;
00757   }
00758 
00759   return NS_OK;
00760 
00761 }
00762 
00763 NS_IMETHODIMP nsRenderingContextGTK::GetLineStyle(nsLineStyle &aLineStyle)
00764 {
00765   aLineStyle = mCurrentLineStyle;
00766   return NS_OK;
00767 }
00768 
00769 NS_IMETHODIMP nsRenderingContextGTK::GetFontMetrics(nsIFontMetrics *&aFontMetrics)
00770 {
00771   NS_IF_ADDREF(mFontMetrics);
00772   aFontMetrics = mFontMetrics;
00773   return NS_OK;
00774 }
00775 
00776 // add the passed in translation to the current translation
00777 NS_IMETHODIMP nsRenderingContextGTK::Translate(nscoord aX, nscoord aY)
00778 {
00779   mTranMatrix->AddTranslation((float)aX,(float)aY);
00780   return NS_OK;
00781 }
00782 
00783 // add the passed in scale to the current scale
00784 NS_IMETHODIMP nsRenderingContextGTK::Scale(float aSx, float aSy)
00785 {
00786   mTranMatrix->AddScale(aSx, aSy);
00787   return NS_OK;
00788 }
00789 
00790 NS_IMETHODIMP nsRenderingContextGTK::GetCurrentTransform(nsTransform2D *&aTransform)
00791 {
00792   aTransform = mTranMatrix;
00793   return NS_OK;
00794 }
00795 
00796 NS_IMETHODIMP nsRenderingContextGTK::CreateDrawingSurface(const nsRect &aBounds,
00797                                                           PRUint32 aSurfFlags,
00798                                                           nsIDrawingSurface* &aSurface)
00799 {
00800   if (nsnull == mSurface) {
00801     aSurface = nsnull;
00802     return NS_ERROR_FAILURE;
00803   }
00804 
00805   g_return_val_if_fail ((aBounds.width > 0) && (aBounds.height > 0), NS_ERROR_FAILURE);
00806  
00807   nsresult rv = NS_OK;
00808   nsDrawingSurfaceGTK *surf = new nsDrawingSurfaceGTK();
00809 
00810   if (surf)
00811   {
00812     NS_ADDREF(surf);
00813     PushState();
00814     mClipRegion = nsnull;
00815     UpdateGC();
00816     rv = surf->Init(mGC, aBounds.width, aBounds.height, aSurfFlags);
00817     PopState();
00818   } else {
00819     rv = NS_ERROR_FAILURE;
00820   }
00821 
00822   aSurface = surf;
00823 
00824   return rv;
00825 }
00826 
00827 NS_IMETHODIMP nsRenderingContextGTK::DestroyDrawingSurface(nsIDrawingSurface* aDS)
00828 {
00829   nsDrawingSurfaceGTK *surf = (nsDrawingSurfaceGTK *) aDS;
00830 
00831   g_return_val_if_fail ((surf != NULL), NS_ERROR_FAILURE);
00832 
00833   NS_IF_RELEASE(surf);
00834 
00835   return NS_OK;
00836 }
00837 
00838 NS_IMETHODIMP nsRenderingContextGTK::DrawLine(nscoord aX0, nscoord aY0, nscoord aX1, nscoord aY1)
00839 {
00840   nscoord diffX,diffY;
00841 
00842   g_return_val_if_fail(mTranMatrix != NULL, NS_ERROR_FAILURE);
00843   g_return_val_if_fail(mSurface != NULL, NS_ERROR_FAILURE);
00844 
00845   mTranMatrix->TransformCoord(&aX0,&aY0);
00846   mTranMatrix->TransformCoord(&aX1,&aY1);
00847 
00848   diffX = aX1-aX0;
00849   diffY = aY1-aY0;
00850 
00851   if (0!=diffX) {
00852     diffX = (diffX>0?1:-1);
00853   }
00854   if (0!=diffY) {
00855     diffY = (diffY>0?1:-1);
00856   }
00857 
00858   UpdateGC();
00859 
00860   ::gdk_draw_line(mSurface->GetDrawable(),
00861                   mGC,
00862                   aX0, aY0, aX1-diffX, aY1-diffY);
00863 
00864   return NS_OK;
00865 }
00866 
00867 NS_IMETHODIMP nsRenderingContextGTK::DrawPolyline(const nsPoint aPoints[], PRInt32 aNumPoints)
00868 {
00869   PRInt32 i;
00870 
00871   g_return_val_if_fail(mTranMatrix != NULL, NS_ERROR_FAILURE);
00872   g_return_val_if_fail(mSurface != NULL, NS_ERROR_FAILURE);
00873 
00874   GdkPoint *pts = new GdkPoint[aNumPoints];
00875   for (i = 0; i < aNumPoints; i++)
00876   {
00877     nsPoint p = aPoints[i];
00878     mTranMatrix->TransformCoord(&p.x,&p.y);
00879     pts[i].x = p.x;
00880     pts[i].y = p.y;
00881   }
00882 
00883   UpdateGC();
00884 
00885   ::gdk_draw_lines(mSurface->GetDrawable(),
00886                    mGC,
00887                    pts, aNumPoints);
00888 
00889   delete[] pts;
00890 
00891   return NS_OK;
00892 }
00893 
00894 NS_IMETHODIMP nsRenderingContextGTK::DrawRect(const nsRect& aRect)
00895 {
00896   return DrawRect(aRect.x, aRect.y, aRect.width, aRect.height);
00897 }
00898 
00899 NS_IMETHODIMP nsRenderingContextGTK::DrawRect(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight)
00900 {
00901   if (nsnull == mTranMatrix || nsnull == mSurface) {
00902     return NS_ERROR_FAILURE;
00903   }
00904 
00905   nscoord x,y,w,h;
00906 
00907   x = aX;
00908   y = aY;
00909   w = aWidth;
00910   h = aHeight;
00911 
00912   g_return_val_if_fail ((mSurface->GetDrawable() != NULL) ||
00913                         (mGC != NULL), NS_ERROR_FAILURE);
00914 
00915   mTranMatrix->TransformCoord(&x,&y,&w,&h);
00916 
00917   // After the transform, if the numbers are huge, chop them, because
00918   // they're going to be converted from 32 bit to 16 bit.
00919   // It's all way off the screen anyway.
00920   ConditionRect(x,y,w,h);
00921 
00922   // Don't draw empty rectangles; also, w/h are adjusted down by one
00923   // so that the right number of pixels are drawn.
00924   if (w && h) {
00925 
00926     UpdateGC();
00927 
00928     ::gdk_draw_rectangle(mSurface->GetDrawable(), mGC,
00929                          FALSE,
00930                          x, y,
00931                          w - 1,
00932                          h - 1);
00933   }
00934 
00935   return NS_OK;
00936 }
00937 
00938 NS_IMETHODIMP nsRenderingContextGTK::FillRect(const nsRect& aRect)
00939 {
00940   return FillRect(aRect.x, aRect.y, aRect.width, aRect.height);
00941 }
00942 
00943 NS_IMETHODIMP nsRenderingContextGTK::FillRect(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight)
00944 {
00945   if (nsnull == mTranMatrix || nsnull == mSurface) {
00946     return NS_ERROR_FAILURE;
00947   }
00948 
00949   nscoord x,y,w,h;
00950 
00951   x = aX;
00952   y = aY;
00953   w = aWidth;
00954   h = aHeight;
00955 
00956   mTranMatrix->TransformCoord(&x,&y,&w,&h);
00957 
00958   // After the transform, if the numbers are huge, chop them, because
00959   // they're going to be converted from 32 bit to 16 bit.
00960   // It's all way off the screen anyway.
00961   ConditionRect(x,y,w,h);
00962 
00963   UpdateGC();
00964 
00965   ::gdk_draw_rectangle(mSurface->GetDrawable(), mGC,
00966                        TRUE,
00967                        x, y, w, h);
00968 
00969   return NS_OK;
00970 }
00971 
00972 NS_IMETHODIMP nsRenderingContextGTK::InvertRect(const nsRect& aRect)
00973 {
00974   return InvertRect(aRect.x, aRect.y, aRect.width, aRect.height);
00975 }
00976 
00977 NS_IMETHODIMP nsRenderingContextGTK::InvertRect(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight)
00978 {
00979   if (nsnull == mTranMatrix || nsnull == mSurface) {
00980     return NS_ERROR_FAILURE;
00981   }
00982 
00983   // Back up the current color, and use GXxor against white to get a
00984   // visible result.
00985   nscolor backupColor = mCurrentColor;
00986   mCurrentColor = NS_RGB(255, 255, 255);
00987   nscoord x,y,w,h;
00988 
00989   x = aX;
00990   y = aY;
00991   w = aWidth;
00992   h = aHeight;
00993 
00994   mTranMatrix->TransformCoord(&x,&y,&w,&h);
00995 
00996   // After the transform, if the numbers are huge, chop them, because
00997   // they're going to be converted from 32 bit to 16 bit.
00998   // It's all way off the screen anyway.
00999   ConditionRect(x,y,w,h);
01000 
01001   mFunction = GDK_XOR;
01002 
01003   UpdateGC();
01004 
01005   // Fill the rect
01006   ::gdk_draw_rectangle(mSurface->GetDrawable(), mGC,
01007                        TRUE,
01008                        x, y, w, h);
01009 
01010   // Back to normal copy drawing mode
01011   mFunction = GDK_COPY;
01012 
01013   // Restore current color
01014   mCurrentColor = backupColor;
01015 
01016   return NS_OK;
01017 }
01018 
01019 NS_IMETHODIMP nsRenderingContextGTK::DrawPolygon(const nsPoint aPoints[], PRInt32 aNumPoints)
01020 {
01021   g_return_val_if_fail(mTranMatrix != NULL, NS_ERROR_FAILURE);
01022   g_return_val_if_fail(mSurface != NULL, NS_ERROR_FAILURE);
01023 
01024   GdkPoint *pts = new GdkPoint[aNumPoints];
01025   for (PRInt32 i = 0; i < aNumPoints; i++)
01026   {
01027     nsPoint p = aPoints[i];
01028     mTranMatrix->TransformCoord(&p.x,&p.y);
01029     pts[i].x = p.x;
01030     pts[i].y = p.y;
01031   }
01032 
01033   UpdateGC();
01034 
01035   ::gdk_draw_polygon(mSurface->GetDrawable(), mGC, FALSE, pts, aNumPoints);
01036 
01037   delete[] pts;
01038 
01039   return NS_OK;
01040 }
01041 
01042 NS_IMETHODIMP nsRenderingContextGTK::FillPolygon(const nsPoint aPoints[], PRInt32 aNumPoints)
01043 {
01044   g_return_val_if_fail(mTranMatrix != NULL, NS_ERROR_FAILURE);
01045   g_return_val_if_fail(mSurface != NULL, NS_ERROR_FAILURE);
01046 
01047   GdkPoint *pts = new GdkPoint[aNumPoints];
01048   for (PRInt32 i = 0; i < aNumPoints; i++)
01049   {
01050     nsPoint p = aPoints[i];
01051     mTranMatrix->TransformCoord(&p.x,&p.y);
01052     pts[i].x = p.x;
01053     pts[i].y = p.y;
01054   }
01055 
01056   UpdateGC();
01057 
01058   ::gdk_draw_polygon(mSurface->GetDrawable(), mGC, TRUE, pts, aNumPoints);
01059 
01060   delete[] pts;
01061 
01062   return NS_OK;
01063 }
01064 
01065 NS_IMETHODIMP nsRenderingContextGTK::DrawEllipse(const nsRect& aRect)
01066 {
01067   return DrawEllipse(aRect.x, aRect.y, aRect.width, aRect.height);
01068 }
01069 
01070 NS_IMETHODIMP nsRenderingContextGTK::DrawEllipse(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight)
01071 {
01072   g_return_val_if_fail(mTranMatrix != NULL, NS_ERROR_FAILURE);
01073   g_return_val_if_fail(mSurface != NULL, NS_ERROR_FAILURE);
01074 
01075   nscoord x,y,w,h;
01076 
01077   x = aX;
01078   y = aY;
01079   w = aWidth;
01080   h = aHeight;
01081 
01082   mTranMatrix->TransformCoord(&x,&y,&w,&h);
01083 
01084   UpdateGC();
01085 
01086   ::gdk_draw_arc(mSurface->GetDrawable(), mGC, FALSE,
01087                  x, y, w, h,
01088                  0, 360 * 64);
01089 
01090   return NS_OK;
01091 }
01092 
01093 NS_IMETHODIMP nsRenderingContextGTK::FillEllipse(const nsRect& aRect)
01094 {
01095   return FillEllipse(aRect.x, aRect.y, aRect.width, aRect.height);
01096 }
01097 
01098 NS_IMETHODIMP nsRenderingContextGTK::FillEllipse(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight)
01099 {
01100   g_return_val_if_fail(mTranMatrix != NULL, NS_ERROR_FAILURE);
01101   g_return_val_if_fail(mSurface != NULL, NS_ERROR_FAILURE);
01102 
01103   nscoord x,y,w,h;
01104 
01105   x = aX;
01106   y = aY;
01107   w = aWidth;
01108   h = aHeight;
01109 
01110   mTranMatrix->TransformCoord(&x,&y,&w,&h);
01111 
01112   UpdateGC();
01113 
01114   if (w < 16 || h < 16) {
01115     /* Fix for bug 91816 ("bullets are not displayed correctly on certain text zooms")
01116      * De-uglify bullets on some X servers:
01117      * 1st: Draw... */
01118     ::gdk_draw_arc(mSurface->GetDrawable(), mGC, FALSE,
01119                    x, y, w, h,
01120                    0, 360 * 64);
01121     /*  ...then fill. */
01122   }
01123   ::gdk_draw_arc(mSurface->GetDrawable(), mGC, TRUE,
01124                  x, y, w, h,
01125                  0, 360 * 64);
01126 
01127   return NS_OK;
01128 }
01129 
01130 NS_IMETHODIMP nsRenderingContextGTK::DrawArc(const nsRect& aRect,
01131                                              float aStartAngle, float aEndAngle)
01132 {
01133   return DrawArc(aRect.x,aRect.y,aRect.width,aRect.height,aStartAngle,aEndAngle);
01134 }
01135 
01136 NS_IMETHODIMP nsRenderingContextGTK::DrawArc(nscoord aX, nscoord aY,
01137                                              nscoord aWidth, nscoord aHeight,
01138                                              float aStartAngle, float aEndAngle)
01139 {
01140   g_return_val_if_fail(mTranMatrix != NULL, NS_ERROR_FAILURE);
01141   g_return_val_if_fail(mSurface != NULL, NS_ERROR_FAILURE);
01142 
01143   nscoord x,y,w,h;
01144 
01145   x = aX;
01146   y = aY;
01147   w = aWidth;
01148   h = aHeight;
01149 
01150   mTranMatrix->TransformCoord(&x,&y,&w,&h);
01151 
01152   UpdateGC();
01153 
01154   ::gdk_draw_arc(mSurface->GetDrawable(), mGC, FALSE,
01155                  x, y, w, h,
01156                  NSToIntRound(aStartAngle * 64.0f),
01157                  NSToIntRound(aEndAngle * 64.0f));
01158 
01159   return NS_OK;
01160 }
01161 
01162 NS_IMETHODIMP nsRenderingContextGTK::FillArc(const nsRect& aRect,
01163                                              float aStartAngle, float aEndAngle)
01164 {
01165   return FillArc(aRect.x,aRect.y,aRect.width,aRect.height,aStartAngle,aEndAngle);
01166 }
01167 
01168 
01169 NS_IMETHODIMP nsRenderingContextGTK::FillArc(nscoord aX, nscoord aY,
01170                                              nscoord aWidth, nscoord aHeight,
01171                                              float aStartAngle, float aEndAngle)
01172 {
01173   g_return_val_if_fail(mTranMatrix != NULL, NS_ERROR_FAILURE);
01174   g_return_val_if_fail(mSurface != NULL, NS_ERROR_FAILURE);
01175 
01176   nscoord x,y,w,h;
01177 
01178   x = aX;
01179   y = aY;
01180   w = aWidth;
01181   h = aHeight;
01182 
01183   mTranMatrix->TransformCoord(&x,&y,&w,&h);
01184 
01185   UpdateGC();
01186 
01187   ::gdk_draw_arc(mSurface->GetDrawable(), mGC, TRUE,
01188                  x, y, w, h,
01189                  NSToIntRound(aStartAngle * 64.0f),
01190                  NSToIntRound(aEndAngle * 64.0f));
01191 
01192   return NS_OK;
01193 }
01194 
01195 NS_IMETHODIMP
01196 nsRenderingContextGTK::GetWidth(char aC, nscoord &aWidth)
01197 {
01198     // Check for the very common case of trying to get the width of a single
01199     // space.
01200   if ((aC == ' ') && (nsnull != mFontMetrics)) {
01201     return mFontMetrics->GetSpaceWidth(aWidth);
01202   }
01203   return GetWidth(&aC, 1, aWidth);
01204 }
01205 
01206 NS_IMETHODIMP
01207 nsRenderingContextGTK::GetWidth(PRUnichar aC, nscoord& aWidth,
01208                                 PRInt32* aFontID)
01209 {
01210   return GetWidth(&aC, 1, aWidth, aFontID);
01211 }
01212 
01213 NS_IMETHODIMP
01214 nsRenderingContextGTK::GetWidthInternal(const char* aString, PRUint32 aLength,
01215                                         nscoord& aWidth)
01216 {
01217   if (0 == aLength) {
01218     aWidth = 0;
01219     return NS_OK;
01220   }
01221 
01222   g_return_val_if_fail(aString != NULL, NS_ERROR_FAILURE);
01223 
01224   return mFontMetrics->GetWidth(aString, aLength, aWidth, this);
01225 }
01226 
01227 NS_IMETHODIMP
01228 nsRenderingContextGTK::GetWidthInternal(const PRUnichar* aString, PRUint32 aLength,
01229                                         nscoord& aWidth, PRInt32* aFontID)
01230 {
01231   if (0 == aLength) {
01232     aWidth = 0;
01233     return NS_OK;
01234   }
01235 
01236   g_return_val_if_fail(aString != NULL, NS_ERROR_FAILURE);
01237 
01238   return mFontMetrics->GetWidth(aString, aLength, aWidth, aFontID, this);
01239 }
01240 
01241 NS_IMETHODIMP
01242 nsRenderingContextGTK::GetTextDimensionsInternal(const char* aString, PRUint32 aLength,
01243                                                  nsTextDimensions& aDimensions)
01244 {
01245   mFontMetrics->GetMaxAscent(aDimensions.ascent);
01246   mFontMetrics->GetMaxDescent(aDimensions.descent);
01247   return GetWidth(aString, aLength, aDimensions.width);
01248 }
01249 
01250 NS_IMETHODIMP
01251 nsRenderingContextGTK::GetTextDimensionsInternal(const PRUnichar* aString,
01252                                                  PRUint32 aLength,
01253                                                  nsTextDimensions& aDimensions, 
01254                                                  PRInt32* aFontID)
01255 {
01256   return mFontMetrics->GetTextDimensions(aString, aLength, aDimensions,
01257                                          aFontID, this);
01258 }
01259 
01260 NS_IMETHODIMP
01261 nsRenderingContextGTK::GetTextDimensionsInternal(const char*       aString,
01262                                                  PRInt32           aLength,
01263                                                  PRInt32           aAvailWidth,
01264                                                  PRInt32*          aBreaks,
01265                                                  PRInt32           aNumBreaks,
01266                                                  nsTextDimensions& aDimensions,
01267                                                  PRInt32&          aNumCharsFit,
01268                                                  nsTextDimensions& aLastWordDimensions,
01269                                                  PRInt32*          aFontID)
01270 {
01271   return mFontMetrics->GetTextDimensions(aString, aLength, aAvailWidth,
01272                                          aBreaks, aNumBreaks, aDimensions,
01273                                          aNumCharsFit,
01274                                          aLastWordDimensions, aFontID,
01275                                          this);
01276 }
01277 NS_IMETHODIMP
01278 nsRenderingContextGTK::GetTextDimensionsInternal(const PRUnichar*  aString,
01279                                                  PRInt32           aLength,
01280                                                  PRInt32           aAvailWidth,
01281                                                  PRInt32*          aBreaks,
01282                                                  PRInt32           aNumBreaks,
01283                                                  nsTextDimensions& aDimensions,
01284                                                  PRInt32&          aNumCharsFit,
01285                                                  nsTextDimensions& aLastWordDimensions,
01286                                                  PRInt32*          aFontID)
01287 {
01288   return mFontMetrics->GetTextDimensions(aString, aLength, aAvailWidth,
01289                                          aBreaks, aNumBreaks, aDimensions,
01290                                          aNumCharsFit,
01291                                          aLastWordDimensions, aFontID,
01292                                          this);
01293 }
01294 
01295 NS_IMETHODIMP
01296 nsRenderingContextGTK::DrawStringInternal(const char *aString, PRUint32 aLength,
01297                                           nscoord aX, nscoord aY,
01298                                           const nscoord* aSpacing)
01299 {
01300   return mFontMetrics->DrawString(aString, aLength, aX, aY, aSpacing,
01301                                   this, mSurface);
01302 }
01303 
01304 NS_IMETHODIMP
01305 nsRenderingContextGTK::DrawStringInternal(const PRUnichar* aString, PRUint32 aLength,
01306                                           nscoord aX, nscoord aY,
01307                                           PRInt32 aFontID,
01308                                           const nscoord* aSpacing)
01309 {
01310   return mFontMetrics->DrawString(aString, aLength, aX, aY, aFontID,
01311                                   aSpacing, this, mSurface);
01312 }
01313 
01314 NS_IMETHODIMP
01315 nsRenderingContextGTK::CopyOffScreenBits(nsIDrawingSurface* aSrcSurf,
01316                                          PRInt32 aSrcX, PRInt32 aSrcY,
01317                                          const nsRect &aDestBounds,
01318                                          PRUint32 aCopyFlags)
01319 {
01320   PRInt32               srcX = aSrcX;
01321   PRInt32               srcY = aSrcY;
01322   nsRect                drect = aDestBounds;
01323   nsDrawingSurfaceGTK  *destsurf;
01324 
01325   g_return_val_if_fail(aSrcSurf != NULL, NS_ERROR_FAILURE);
01326   g_return_val_if_fail(mTranMatrix != NULL, NS_ERROR_FAILURE);
01327   g_return_val_if_fail(mSurface != NULL, NS_ERROR_FAILURE);
01328 
01329 #if 0
01330   printf("nsRenderingContextGTK::CopyOffScreenBits()\nflags=\n");
01331 
01332   if (aCopyFlags & NS_COPYBITS_USE_SOURCE_CLIP_REGION)
01333     printf("NS_COPYBITS_USE_SOURCE_CLIP_REGION\n");
01334 
01335   if (aCopyFlags & NS_COPYBITS_XFORM_SOURCE_VALUES)
01336     printf("NS_COPYBITS_XFORM_SOURCE_VALUES\n");
01337 
01338   if (aCopyFlags & NS_COPYBITS_XFORM_DEST_VALUES)
01339     printf("NS_COPYBITS_XFORM_DEST_VALUES\n");
01340 
01341   if (aCopyFlags & NS_COPYBITS_TO_BACK_BUFFER)
01342     printf("NS_COPYBITS_TO_BACK_BUFFER\n");
01343 
01344   printf("\n");
01345 #endif
01346 
01347   if (aCopyFlags & NS_COPYBITS_TO_BACK_BUFFER)
01348   {
01349     NS_ASSERTION(!(nsnull == mSurface), "no back buffer");
01350     destsurf = mSurface;
01351   }
01352   else
01353   {
01354     NS_ENSURE_TRUE(mOffscreenSurface != nsnull, NS_ERROR_FAILURE);
01355     destsurf = mOffscreenSurface;
01356   }
01357 
01358   if (aCopyFlags & NS_COPYBITS_XFORM_SOURCE_VALUES)
01359     mTranMatrix->TransformCoord(&srcX, &srcY);
01360 
01361   if (aCopyFlags & NS_COPYBITS_XFORM_DEST_VALUES)
01362     mTranMatrix->TransformCoord(&drect.x, &drect.y, &drect.width, &drect.height);
01363 
01364 #if 0
01365   // XXX implement me
01366   if (aCopyFlags & NS_COPYBITS_USE_SOURCE_CLIP_REGION)
01367   {
01368     // we should use the source clip region if this flag is used...
01369     nsIRegion *region;
01370     CopyClipRegion();
01371   }
01372 #endif
01373 
01374   //XXX flags are unused. that would seem to mean that there is
01375   //inefficiency somewhere... MMP
01376 
01377   // gdk_draw_pixmap and copy_area do the same thing internally.
01378   // copy_area sounds better
01379 
01380   UpdateGC();
01381 
01382   ::gdk_window_copy_area(destsurf->GetDrawable(),
01383                          mGC,
01384                          drect.x, drect.y,
01385                          ((nsDrawingSurfaceGTK *)aSrcSurf)->GetDrawable(),
01386                          srcX, srcY,
01387                          drect.width, drect.height);
01388                      
01389 
01390   return NS_OK;
01391 }
01392 
01393 NS_IMETHODIMP nsRenderingContextGTK::RetrieveCurrentNativeGraphicData(void** ngd)
01394 {
01395   if (ngd) {
01396     if (mSurface)
01397       *ngd = (void*) mSurface->GetDrawable();
01398     else
01399       *ngd = nsnull;
01400   }
01401 
01402   return NS_OK;
01403 }
01404 
01405 #ifdef MOZ_MATHML
01406 
01407 NS_IMETHODIMP
01408 nsRenderingContextGTK::GetBoundingMetricsInternal(const char*        aString, 
01409                                                   PRUint32           aLength,
01410                                                   nsBoundingMetrics& aBoundingMetrics)
01411 {
01412   return mFontMetrics->GetBoundingMetrics(aString, aLength, aBoundingMetrics,
01413                                           this);
01414 }
01415 
01416 NS_IMETHODIMP
01417 nsRenderingContextGTK::GetBoundingMetricsInternal(const PRUnichar*   aString, 
01418                                                   PRUint32           aLength,
01419                                                   nsBoundingMetrics& aBoundingMetrics,
01420                                                   PRInt32*           aFontID)
01421 {
01422   return mFontMetrics->GetBoundingMetrics(aString, aLength, aBoundingMetrics,
01423                                           aFontID, this);
01424 }
01425 
01426 #endif /* MOZ_MATHML */
01427 
01428 NS_IMETHODIMP nsRenderingContextGTK::SetRightToLeftText(PRBool aIsRTL)
01429 {
01430   return mFontMetrics->SetRightToLeftText(aIsRTL);
01431 }
01432 
01433 NS_IMETHODIMP nsRenderingContextGTK::GetRightToLeftText(PRBool* aIsRTL)
01434 {
01435   *aIsRTL = mFontMetrics->GetRightToLeftText();
01436   return NS_OK;
01437 }
01438 
01439 PRInt32 nsRenderingContextGTK::GetMaxStringLength()
01440 {
01441   if (!mFontMetrics)
01442     return 1;
01443   return mFontMetrics->GetMaxStringLength();
01444 }
01445 
01446 NS_IMETHODIMP nsRenderingContextGTK::GetClusterInfo(const PRUnichar *aText,
01447                                                     PRUint32 aLength,
01448                                                     PRUint8 *aClusterStarts)
01449 {
01450   return mFontMetrics->GetClusterInfo(aText, aLength, aClusterStarts);
01451 }
01452 
01453 PRInt32 nsRenderingContextGTK::GetPosition(const PRUnichar *aText, PRUint32 aLength,
01454                                            nsPoint aPt)
01455 {
01456   return mFontMetrics->GetPosition(aText, aLength, aPt);
01457 }
01458 
01459 NS_IMETHODIMP nsRenderingContextGTK::GetRangeWidth(const PRUnichar *aText, PRUint32 aLength,
01460                                                    PRUint32 aStart, PRUint32 aEnd,
01461                                                    PRUint32 &aWidth)
01462 {
01463   return mFontMetrics->GetRangeWidth(aText, aLength, aStart, aEnd, aWidth);
01464 }
01465 
01466 NS_IMETHODIMP nsRenderingContextGTK::GetRangeWidth(const char *aText, PRUint32 aLength,
01467                                                    PRUint32 aStart, PRUint32 aEnd,
01468                                                    PRUint32 &aWidth)
01469 {
01470   return mFontMetrics->GetRangeWidth(aText, aLength, aStart, aEnd, aWidth);
01471 }
01472 
01473 NS_IMETHODIMP nsRenderingContextGTK::DrawImage(imgIContainer *aImage, const nsRect & aSrcRect, const nsRect & aDestRect)
01474 {
01475   UpdateGC();
01476   return nsRenderingContextImpl::DrawImage(aImage, aSrcRect, aDestRect);
01477 }
01478 
01479 NS_IMETHODIMP nsRenderingContextGTK::GetBackbuffer(const nsRect &aRequestedSize,
01480                                                    const nsRect &aMaxSize,
01481                                                    PRBool aForBlending,
01482                                                    nsIDrawingSurface* &aBackbuffer)
01483 {
01484   // Do not cache the backbuffer. On GTK it is more efficient to allocate
01485   // the backbuffer as needed and it doesn't cause a performance hit. @see bug 95952
01486   return AllocateBackbuffer(aRequestedSize, aMaxSize, aBackbuffer, PR_FALSE, 0);
01487 }
01488  
01489 NS_IMETHODIMP nsRenderingContextGTK::ReleaseBackbuffer(void) {
01490   // Do not cache the backbuffer. On GTK it is more efficient to allocate
01491   // the backbuffer as needed and it doesn't cause a performance hit. @see bug 95952
01492   return DestroyCachedBackbuffer();
01493 }