Back to index

lightning-sunbird  0.9+nobinonly
nsRenderingContextXlib.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  *   Peter Hartshorn <peter@igelaus.com.au>
00024  *   Ken Faulkner <faulkner@igelaus.com.au>
00025  *   Tony Tsui <tony@igelaus.com.au>
00026  *   Tomi Leppikangas <tomi.leppikangas@oulu.fi>
00027  *   Tim Copperfield <timecop@network.email.ne.jp>
00028  *   Roland Mainz <roland.mainz@informatik.med.uni-giessen.de>
00029  *
00030  * Alternatively, the contents of this file may be used under the terms of
00031  * either of the GNU General Public License Version 2 or later (the "GPL"),
00032  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00033  * in which case the provisions of the GPL or the LGPL are applicable instead
00034  * of those above. If you wish to allow use of your version of this file only
00035  * under the terms of either the GPL or the LGPL, and not to allow others to
00036  * use your version of this file under the terms of the MPL, indicate your
00037  * decision by deleting the provisions above and replace them with the notice
00038  * and other provisions required by the GPL or the LGPL. If you do not delete
00039  * the provisions above, a recipient may use your version of this file under
00040  * the terms of any one of the MPL, the GPL or the LGPL.
00041  *
00042  * ***** END LICENSE BLOCK ***** */
00043 
00044 #include "nsRenderingContextXlib.h"
00045 #include "nsFontMetricsXlib.h"
00046 #include "nsCompressedCharMap.h"
00047 #include "xlibrgb.h"
00048 #include "prprf.h"
00049 #include "prmem.h"
00050 #include "prlog.h"
00051 #include "prenv.h"
00052 #include "nsGCCache.h"
00053 #include "imgIContainer.h"
00054 #include "gfxIImageFrame.h"
00055 #include "nsIInterfaceRequestor.h"
00056 #include "nsIInterfaceRequestorUtils.h"
00057 
00058 #define NS_TO_XLIBRGB_RGB(ns) (ns & 0xff) << 16 | (ns & 0xff00) | ((ns >> 16) & 0xff)
00059 
00060 NS_IMPL_ISUPPORTS1(nsRenderingContextXlib, nsIRenderingContext)
00061 
00062 #ifdef PR_LOGGING 
00063 static PRLogModuleInfo * RenderingContextXlibLM = PR_NewLogModule("RenderingContextXlib");
00064 #endif /* PR_LOGGING */ 
00065 
00066 /* Handle drawing 8 bit data with a 16 bit font */
00067 static void Widen8To16AndDraw(Drawable    drawable,
00068                               nsXFont     *font,
00069                               GC           gc,
00070                               int          x,
00071                               int          y,
00072                               const char  *text,
00073                               int          text_length);
00074 
00075 
00076 nsresult CreateRenderingContextXlibContext(nsIDeviceContext *aDevice, nsRenderingContextXlibContext **aContext)
00077 {
00078   nsRenderingContextXlibContext *rcctx;
00079   
00080   *aContext = nsnull;
00081   
00082   rcctx = new nsRenderingContextXlibContext();
00083   if (!rcctx)
00084     return NS_ERROR_OUT_OF_MEMORY;
00085   
00086   /* No |Init()|-function to call (yet) */ 
00087   *aContext = rcctx;
00088   
00089   return NS_OK;
00090 }
00091 
00092 void DeleteRenderingContextXlibContext(nsRenderingContextXlibContext *aContext)
00093 {
00094   if (aContext) {
00095     delete aContext;
00096   }
00097 }
00098 
00099 class GraphicsState
00100 {
00101 public:
00102   GraphicsState();
00103   ~GraphicsState();
00104 
00105   nsTransform2D           *mMatrix;
00106   nsCOMPtr<nsIRegion>      mClipRegion;
00107   nscolor                  mColor;
00108   nsLineStyle              mLineStyle;
00109   nsCOMPtr<nsIFontMetrics> mFontMetrics;
00110 };
00111 
00112 MOZ_DECL_CTOR_COUNTER(GraphicsState)
00113 
00114 GraphicsState::GraphicsState() :
00115   mMatrix(nsnull),
00116   mColor(NS_RGB(0, 0, 0)),
00117   mLineStyle(nsLineStyle_kSolid),
00118   mFontMetrics(nsnull)
00119 {
00120   MOZ_COUNT_CTOR(GraphicsState);
00121 
00122 }
00123 
00124 GraphicsState::~GraphicsState()
00125 {
00126   MOZ_COUNT_DTOR(GraphicsState);
00127 }
00128 
00129 
00130 nsRenderingContextXlib::nsRenderingContextXlib() :
00131   nsRenderingContextImpl(),
00132   mP2T(1.0f),
00133   mGC(nsnull),
00134   mFunction(GXcopy),
00135   mCurrentColor(NS_RGB(0, 0, 0)), /* X11 intial bg color is always _black_...
00136                                    * ...but we should query that from 
00137                                    * Xserver instead of guessing that...
00138                                    */
00139   mCurrentFont(nsnull),
00140   mCurrentLineStyle(nsLineStyle_kSolid)
00141 {
00142   PR_LOG(RenderingContextXlibLM, PR_LOG_DEBUG, ("nsRenderingContextXlib::nsRenderingContextXlib()\n"));
00143 
00144   PushState();
00145 }
00146 
00147 nsRenderingContextXlib::~nsRenderingContextXlib()
00148 {
00149   PR_LOG(RenderingContextXlibLM, PR_LOG_DEBUG, ("nsRenderingContextXlib::~nsRenderingContextXlib()\n"));
00150   /* Destroy the State Machine */
00151   PRInt32 cnt = mStateCache.Count();
00152 
00153   while (--cnt >= 0)
00154     PopState();
00155 
00156   if (mTranMatrix)
00157     delete mTranMatrix;
00158   
00159   if (mGC)
00160     mGC->Release();
00161 }
00162 
00163 NS_IMETHODIMP
00164 nsRenderingContextXlib::Init(nsIDeviceContext* aContext, nsIWidget *aWindow)
00165 {
00166   PR_LOG(RenderingContextXlibLM, PR_LOG_DEBUG, ("nsRenderingContextXlib::Init(DeviceContext, Widget)\n"));
00167   nsDrawingSurfaceXlibImpl *surf; // saves some cast stunts
00168 
00169   NS_ENSURE_TRUE(aContext != nsnull, NS_ERROR_NULL_POINTER);
00170   NS_ENSURE_TRUE(aWindow  != nsnull, NS_ERROR_NULL_POINTER);
00171   mContext = aContext;
00172   
00173   nsIDeviceContext *dc = mContext;     
00174   NS_STATIC_CAST(nsDeviceContextX *, dc)->GetXlibRgbHandle(mXlibRgbHandle);
00175   mDisplay = xxlib_rgb_get_display(mXlibRgbHandle);
00176 
00177   surf = new nsDrawingSurfaceXlibImpl();
00178 
00179   if (surf) {
00180     Drawable  win = (Drawable)aWindow->GetNativeData(NS_NATIVE_WINDOW);
00181     xGC      *gc  = (xGC *)aWindow->GetNativeData(NS_NATIVE_GRAPHIC);
00182 
00183     surf->Init(mXlibRgbHandle, 
00184                win, 
00185                gc);
00186 
00187     mOffscreenSurface = mSurface = surf;
00188     /* aWindow->GetNativeData() ref'd the gc */
00189     gc->Release();
00190   }
00191 
00192   return CommonInit();
00193 }
00194 
00195 NS_IMETHODIMP
00196 nsRenderingContextXlib::Init(nsIDeviceContext* aContext, nsIDrawingSurface* aSurface)
00197 {
00198   PR_LOG(RenderingContextXlibLM, PR_LOG_DEBUG, ("nsRenderingContxtXlib::Init(DeviceContext, DrawingSurface)\n"));
00199 
00200   NS_ENSURE_TRUE(nsnull != aContext, NS_ERROR_NULL_POINTER);
00201   mContext = aContext;
00202   
00203   nsIDeviceContext *dc = mContext;     
00204   NS_STATIC_CAST(nsDeviceContextX *, dc)->GetXlibRgbHandle(mXlibRgbHandle);
00205   mDisplay = xxlib_rgb_get_display(mXlibRgbHandle);
00206 
00207   mSurface = (nsIDrawingSurfaceXlib *)aSurface;
00208   mOffscreenSurface = mSurface;
00209 
00210   return CommonInit();
00211 }
00212 
00213 nsresult nsRenderingContextXlib::CommonInit(void)
00214 {
00215   PR_LOG(RenderingContextXlibLM, PR_LOG_DEBUG, ("nsRenderingContxtXlib::CommonInit()\n"));
00216   // put common stuff in here.
00217   int x, y;
00218   unsigned int width, height, border, depth;
00219   Window root_win;
00220 
00221   Drawable drawable; mSurface->GetDrawable(drawable);
00222 
00223   ::XGetGeometry(mDisplay, 
00224                  drawable, 
00225                  &root_win,
00226                  &x, 
00227                  &y, 
00228                  &width, 
00229                  &height, 
00230                  &border, 
00231                  &depth);
00232 
00233   PR_LOG(RenderingContextXlibLM, PR_LOG_DEBUG, 
00234          ("XGetGeometry(display=%lx,drawable=%lx) ="
00235          " {root_win=%lx, x=%d, y=%d, width=%d, height=%d. border=%d, depth=%d}\n",
00236          (long)mDisplay, (long)drawable,
00237          (long)root_win, (int)x, (int)y, (int)width, (int)height, (int)border, (int)depth));
00238 
00239   mClipRegion = new nsRegionXlib();
00240   if (!mClipRegion)
00241     return NS_ERROR_OUT_OF_MEMORY;
00242   mClipRegion->Init();
00243   mClipRegion->SetTo(0, 0, width, height);
00244 
00245   mP2T = mContext->DevUnitsToAppUnits();
00246   float app2dev;
00247   app2dev = mContext->AppUnitsToDevUnits();
00248   mTranMatrix->AddScale(app2dev, app2dev);
00249   return NS_OK;
00250 }
00251 
00252 
00253 NS_IMETHODIMP
00254 nsRenderingContextXlib::GetHints(PRUint32& aResult)
00255 {
00256   PRUint32 result = 0;
00257 
00258   // Most X servers implement 8 bit text rendering alot faster than
00259   // XChar2b rendering. In addition, we can avoid the PRUnichar to
00260   // XChar2b conversion. So we set this bit...
00261   result |= NS_RENDERING_HINT_FAST_8BIT_TEXT;
00262   
00263 /* We can't enable fast text measuring (yet) on platforms
00264  * which force natural alignment of datatypes (see 
00265  * http://bugzilla.mozilla.org/show_bug.cgi?id=36146#c46) ... ;-(
00266  */
00267 #ifndef CPU_DOES_NOT_REQUIRE_NATURAL_ALIGNMENT
00268 #if defined(__i386)
00269 #define CPU_DOES_NOT_REQUIRE_NATURAL_ALIGNMENT 1
00270 #endif /* __i386 */
00271 #endif /* !CPU_DOES_NOT_REQUIRE_NATURAL_ALIGNMENT */
00272 
00273   static PRBool enable_fast_measure;
00274   static PRBool getenv_done = PR_FALSE;
00275 
00276   /* Check for the env vars "MOZILLA_GFX_ENABLE_FAST_MEASURE" and
00277    * "MOZILLA_GFX_DISABLE_FAST_MEASURE" to enable/disable fast text
00278    * measuring (for debugging the feature and doing regression tests).
00279    * This code will be removed one all issues around this new feature have
00280    * been fixed. */
00281   if (!getenv_done)
00282   {
00283 #ifdef CPU_DOES_NOT_REQUIRE_NATURAL_ALIGNMENT
00284     enable_fast_measure = PR_TRUE;
00285 #else
00286     enable_fast_measure = PR_FALSE;
00287 #endif /* CPU_DOES_NOT_REQUIRE_NATURAL_ALIGNMENT */
00288 
00289     if (PR_GetEnv("MOZILLA_GFX_ENABLE_FAST_MEASURE"))
00290     {
00291       enable_fast_measure = PR_TRUE;
00292     }
00293 
00294     if (PR_GetEnv("MOZILLA_GFX_DISABLE_FAST_MEASURE"))
00295     {
00296       enable_fast_measure = PR_FALSE;
00297     }
00298         
00299     getenv_done = PR_TRUE;
00300   } 
00301 
00302   if (enable_fast_measure) {
00303     // We have GetTextDimensions()
00304     result |= NS_RENDERING_HINT_FAST_MEASURE;
00305   }
00306 
00307   // XXX see if we are rendering to the local display or to a remote
00308   // dispaly and set the NS_RENDERING_HINT_REMOTE_RENDERING accordingly
00309 
00310   aResult = result;
00311   return NS_OK;
00312 }
00313 
00314 NS_IMETHODIMP
00315 nsRenderingContextXlib::LockDrawingSurface(PRInt32 aX, PRInt32 aY,
00316                                            PRUint32 aWidth, PRUint32 aHeight,
00317                                            void **aBits, PRInt32 *aStride,
00318                                            PRInt32 *aWidthBytes, PRUint32 aFlags)
00319 {
00320   PR_LOG(RenderingContextXlibLM, PR_LOG_DEBUG, ("nsRenderingContextXlib::LockDrawingSurface()\n"));
00321   PushState();
00322 
00323   return mSurface->Lock(aX, aY, aWidth, aHeight,
00324                         aBits, aStride, aWidthBytes, aFlags);
00325 }
00326 
00327 NS_IMETHODIMP
00328 nsRenderingContextXlib::UnlockDrawingSurface(void)
00329 {
00330   PR_LOG(RenderingContextXlibLM, PR_LOG_DEBUG, ("nsRenderingContextXlib::UnlockDrawingSurface()\n"));
00331   PopState();
00332 
00333   mSurface->Unlock();
00334   
00335   return NS_OK;
00336 }
00337 
00338 NS_IMETHODIMP
00339 nsRenderingContextXlib::SelectOffScreenDrawingSurface(nsIDrawingSurface* aSurface)
00340 {
00341   PR_LOG(RenderingContextXlibLM, PR_LOG_DEBUG, ("nsRenderingContextXlib::SelectOffScreenDrawingSurface()\n"));
00342   if (nsnull == aSurface)
00343     mSurface = mOffscreenSurface;
00344   else
00345     mSurface = (nsIDrawingSurfaceXlib *)aSurface;
00346 
00347   return NS_OK;
00348 }
00349 
00350 NS_IMETHODIMP
00351 nsRenderingContextXlib::GetDrawingSurface(nsIDrawingSurface* *aSurface)
00352 {
00353   PR_LOG(RenderingContextXlibLM, PR_LOG_DEBUG, ("nsRenderingContextXlib::GetDrawingSurface()\n"));
00354   *aSurface = mSurface;
00355   return NS_OK;
00356 }
00357 
00358 NS_IMETHODIMP
00359 nsRenderingContextXlib::Reset()
00360 {
00361   PR_LOG(RenderingContextXlibLM, PR_LOG_DEBUG, ("nsRenderingContextXlib::Reset()\n"));
00362   return NS_OK;
00363 }
00364 
00365 NS_IMETHODIMP nsRenderingContextXlib::GetDeviceContext(nsIDeviceContext *&aContext)
00366 {
00367   aContext = mContext;
00368   NS_IF_ADDREF(aContext);
00369   return NS_OK;
00370 }
00371 
00372 NS_IMETHODIMP
00373 nsRenderingContextXlib::PushState(void)
00374 {
00375   PR_LOG(RenderingContextXlibLM, PR_LOG_DEBUG, ("nsRenderingContextXlib::PushState()\n"));
00376   GraphicsState *state = new GraphicsState();
00377 
00378   if (!state)
00379     return NS_ERROR_OUT_OF_MEMORY;
00380 
00381   state->mMatrix = mTranMatrix;
00382   
00383   mStateCache.AppendElement(state);
00384   
00385   if (nsnull == mTranMatrix)
00386     mTranMatrix = new nsTransform2D();
00387   else
00388     mTranMatrix = new nsTransform2D(mTranMatrix);
00389   
00390   if (mClipRegion) {
00391     state->mClipRegion = mClipRegion;
00392     mClipRegion = new nsRegionXlib();
00393     if (!mClipRegion)
00394       return NS_ERROR_OUT_OF_MEMORY;
00395     mClipRegion->Init();
00396     mClipRegion->SetTo(*state->mClipRegion);
00397   }
00398   
00399   state->mFontMetrics = mFontMetrics;
00400   state->mColor       = mCurrentColor;
00401   state->mLineStyle   = mCurrentLineStyle;
00402   
00403   return NS_OK;
00404 }
00405 
00406 NS_IMETHODIMP
00407 nsRenderingContextXlib::PopState(void)
00408 {
00409   PR_LOG(RenderingContextXlibLM, PR_LOG_DEBUG, ("nsRenderingContextXlib::PopState()\n"));
00410 
00411   PRUint32 cnt = mStateCache.Count();
00412   GraphicsState *state;
00413   
00414   if (cnt > 0) {
00415     state = (GraphicsState *)mStateCache.ElementAt(cnt - 1);
00416     mStateCache.RemoveElementAt(cnt - 1);
00417     
00418     if (mTranMatrix)
00419       delete mTranMatrix;
00420     mTranMatrix = state->mMatrix;
00421     
00422     mClipRegion = state->mClipRegion;
00423     if (mFontMetrics != state->mFontMetrics)
00424       SetFont(state->mFontMetrics);
00425 
00426     if (state->mColor != mCurrentColor)
00427       SetColor(state->mColor);
00428     if (state->mLineStyle != mCurrentLineStyle)
00429       SetLineStyle(state->mLineStyle);
00430 
00431     delete state;
00432   }
00433 
00434   return NS_OK;
00435 }
00436 
00437 #ifdef DEBUG
00438 #undef TRACE_SET_CLIP
00439 #endif
00440 
00441 #ifdef TRACE_SET_CLIP
00442 static char *
00443 nsClipCombine_to_string(nsClipCombine aCombine)
00444 {
00445 #ifdef TRACE_SET_CLIP
00446   printf("nsRenderingContextXlib::SetClipRect(x=%d,y=%d,w=%d,h=%d,%s)\n",
00447          trect.x,
00448          trect.y,
00449          trect.width,
00450          trect.height,
00451          nsClipCombine_to_string(aCombine));
00452 #endif // TRACE_SET_CLIP
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 NS_IMETHODIMP
00478 nsRenderingContextXlib::IsVisibleRect(const nsRect& aRect, PRBool &aVisible)
00479 {
00480   PR_LOG(RenderingContextXlibLM, PR_LOG_DEBUG, ("nsRenderingContextXlib::IsVisibleRect()\n"));
00481   aVisible = PR_TRUE;
00482   return NS_OK;
00483 }
00484 
00485 NS_IMETHODIMP 
00486 nsRenderingContextXlib::SetClipRect(const nsRect& aRect,
00487                                     nsClipCombine aCombine)
00488 {
00489   PR_LOG(RenderingContextXlibLM, PR_LOG_DEBUG, ("nsRenderingContextXlib::SetClipRect()\n"));
00490   nsRect trect = aRect;
00491   mTranMatrix->TransformCoord(&trect.x, &trect.y,
00492                               &trect.width, &trect.height);
00493   SetClipRectInPixels(trect, aCombine);
00494   return NS_OK;
00495 }
00496 
00497 void nsRenderingContextXlib::SetClipRectInPixels(const nsRect& aRect,
00498                                                  nsClipCombine aCombine)
00499 {
00500   PR_LOG(RenderingContextXlibLM, PR_LOG_DEBUG, ("nsRenderingContextXlib::SetClipRectInPixels()\n"));
00501 
00502   switch(aCombine)
00503   {
00504     case nsClipCombine_kIntersect:
00505       mClipRegion->Intersect(aRect.x,aRect.y,aRect.width,aRect.height);
00506       break;
00507     case nsClipCombine_kUnion:
00508       mClipRegion->Union(aRect.x,aRect.y,aRect.width,aRect.height);
00509       break;
00510     case nsClipCombine_kSubtract:
00511       mClipRegion->Subtract(aRect.x,aRect.y,aRect.width,aRect.height);
00512       break;
00513     case nsClipCombine_kReplace:
00514       mClipRegion->SetTo(aRect.x,aRect.y,aRect.width,aRect.height);
00515       break;
00516   }
00517 }
00518 
00519 NS_IMETHODIMP
00520 nsRenderingContextXlib::GetClipRect(nsRect &aRect, PRBool &aClipState)
00521 {
00522   PR_LOG(RenderingContextXlibLM, PR_LOG_DEBUG, ("nsRenderingContextXlib::GetClipRext()\n"));
00523   PRInt32 x, y, w, h;
00524   if (!mClipRegion->IsEmpty()) {
00525     mClipRegion->GetBoundingBox(&x,&y,&w,&h);
00526     aRect.SetRect(x,y,w,h);
00527     aClipState = PR_TRUE;
00528   } else {
00529     aRect.SetRect(0,0,0,0);
00530     aClipState = PR_FALSE;
00531   }
00532   return NS_OK;
00533 }
00534 
00535 NS_IMETHODIMP
00536 nsRenderingContextXlib::SetClipRegion(const nsIRegion& aRegion, nsClipCombine aCombine)
00537 {
00538   PR_LOG(RenderingContextXlibLM, PR_LOG_DEBUG, ("nsRenderingContextXlib::SetClipRegion()\n"));
00539   switch(aCombine)
00540   {
00541     case nsClipCombine_kIntersect:
00542       mClipRegion->Intersect(aRegion);
00543       break;
00544     case nsClipCombine_kUnion:
00545       mClipRegion->Union(aRegion);
00546       break;
00547     case nsClipCombine_kSubtract:
00548       mClipRegion->Subtract(aRegion);
00549       break;
00550     case nsClipCombine_kReplace:
00551       mClipRegion->SetTo(aRegion);
00552       break;
00553   }
00554 
00555   return NS_OK;
00556 }
00557 
00558 NS_IMETHODIMP
00559 nsRenderingContextXlib::CopyClipRegion(nsIRegion &aRegion)
00560 {
00561   PR_LOG(RenderingContextXlibLM, PR_LOG_DEBUG, ("nsRenderingContextXlib::CopyClipRegion()\n"));
00562   aRegion.SetTo(*mClipRegion);
00563   return NS_OK;
00564 }
00565 
00566 NS_IMETHODIMP
00567 nsRenderingContextXlib::GetClipRegion(nsIRegion **aRegion)
00568 {
00569   PR_LOG(RenderingContextXlibLM, PR_LOG_DEBUG, ("nsRenderingContextXlib::GetClipRegion()\n"));
00570   nsresult  rv = NS_OK;
00571   
00572   NS_ASSERTION(!(nsnull == aRegion), "no region ptr");
00573   
00574   if (*aRegion) {
00575     (*aRegion)->SetTo(*mClipRegion);
00576   }
00577   return rv;
00578 }
00579 
00580 void nsRenderingContextXlib::UpdateGC()
00581 {
00582    PR_LOG(RenderingContextXlibLM, PR_LOG_DEBUG, ("nsRenderingContextXlib::UpdateGC()\n"));
00583    XGCValues     values;
00584    unsigned long valuesMask = 0;
00585 
00586    Drawable drawable; mOffscreenSurface->GetDrawable(drawable);
00587  
00588    if (mGC)
00589      mGC->Release();
00590  
00591    memset(&values, 0, sizeof(XGCValues));
00592  
00593    unsigned long color;
00594    color = xxlib_rgb_xpixel_from_rgb (mXlibRgbHandle,
00595                                       NS_RGB(NS_GET_B(mCurrentColor),
00596                                              NS_GET_G(mCurrentColor),
00597                                              NS_GET_R(mCurrentColor)));
00598    values.foreground = color;
00599    valuesMask |= GCForeground;
00600 
00601    if (mCurrentFont && mCurrentFont->GetXFontStruct()) {
00602      valuesMask |= GCFont;
00603      values.font = mCurrentFont->GetXFontStruct()->fid;
00604    }
00605  
00606    values.line_style = mLineStyle;
00607    valuesMask |= GCLineStyle;
00608  
00609    values.function = mFunction;
00610    valuesMask |= GCFunction;
00611 
00612    Region rgn = nsnull;
00613    if (mClipRegion) { 
00614      mClipRegion->GetNativeRegion((void*&)rgn);
00615    }
00616 
00617    nsRenderingContextXlibContext *rcContext;
00618    nsIDeviceContext *dc = mContext;
00619    NS_STATIC_CAST(nsDeviceContextX *, dc)->GetRCContext(rcContext);
00620    
00621    mGC = rcContext->mGcCache.GetGC(mDisplay, drawable,
00622                                   valuesMask, &values, rgn);
00623 }
00624 
00625 NS_IMETHODIMP
00626 nsRenderingContextXlib::SetColor(nscolor aColor)
00627 {
00628   PR_LOG(RenderingContextXlibLM, PR_LOG_DEBUG, ("nsRenderingContextXlib::SetColor(nscolor)\n"));
00629   NS_ENSURE_TRUE(mContext != nsnull, NS_ERROR_FAILURE);
00630 
00631   mCurrentColor = aColor;
00632 
00633   PR_LOG(RenderingContextXlibLM, PR_LOG_DEBUG, ("Setting color to %d %d %d\n", NS_GET_R(aColor), NS_GET_G(aColor), NS_GET_B(aColor)));
00634   return NS_OK;
00635 }
00636 
00637 NS_IMETHODIMP
00638 nsRenderingContextXlib::GetColor(nscolor &aColor) const
00639 {
00640   PR_LOG(RenderingContextXlibLM, PR_LOG_DEBUG, ("nsRenderingContextXlib::GetColor()\n"));
00641 
00642   aColor = mCurrentColor;
00643   return NS_OK;
00644 }
00645 
00646 NS_IMETHODIMP
00647 nsRenderingContextXlib::SetFont(const nsFont& aFont, nsIAtom* aLangGroup)
00648 {
00649   nsCOMPtr<nsIFontMetrics> newMetrics;
00650   nsresult rv = mContext->GetMetricsFor( aFont, aLangGroup, *getter_AddRefs(newMetrics) );
00651 
00652   if (NS_SUCCEEDED(rv)) {
00653     rv = SetFont(newMetrics);
00654   }
00655   return rv;
00656 }
00657 
00658 NS_IMETHODIMP
00659 nsRenderingContextXlib::SetFont(nsIFontMetrics *aFontMetrics)
00660 {
00661   PR_LOG(RenderingContextXlibLM, PR_LOG_DEBUG, ("nsRenderingContextXlib::SetFont()\n"));
00662 
00663   mFontMetrics = aFontMetrics;
00664 
00665   if (mFontMetrics)
00666   {
00667     nsFontHandle  fontHandle;
00668     mFontMetrics->GetFontHandle(fontHandle);
00669     mCurrentFont = (nsFontXlib *)fontHandle;
00670   }
00671 
00672   return NS_OK;
00673 }
00674 
00675 NS_IMETHODIMP
00676 nsRenderingContextXlib::SetLineStyle(nsLineStyle aLineStyle)
00677 {
00678   PR_LOG(RenderingContextXlibLM, PR_LOG_DEBUG, ("nsRenderingContextXlib::SetLineStyle()\n"));
00679 
00680   if (aLineStyle != mCurrentLineStyle) {
00681     /* XXX this isnt done in gtk, copy from there when ready
00682     switch(aLineStyle)
00683       { 
00684       case nsLineStyle_kSolid:
00685         mLineStyle = LineSolid;
00686         mDashes = 0;
00687         break;
00688       case nsLineStyle_kDashed:
00689           static char dashed[2] = {4,4};
00690         mDashList = dashed;
00691         mDashes = 2;
00692         break;
00693       case nsLineStyle_kDotted:
00694           static char dotted[2] = {3,1};
00695         mDashList = dotted;
00696         mDashes = 2;
00697         break;
00698     default:
00699         break;
00700 
00701     }
00702     */
00703     mCurrentLineStyle = aLineStyle ;
00704   }
00705   return NS_OK;
00706 }
00707 
00708 NS_IMETHODIMP
00709 nsRenderingContextXlib::GetLineStyle(nsLineStyle &aLineStyle)
00710 {
00711   PR_LOG(RenderingContextXlibLM, PR_LOG_DEBUG, ("nsRenderingContextXlib::GetLineStyle()\n"));
00712   aLineStyle = mCurrentLineStyle;
00713   return NS_OK;
00714 }
00715 
00716 NS_IMETHODIMP
00717 nsRenderingContextXlib::GetFontMetrics(nsIFontMetrics *&aFontMetrics)
00718 {
00719   PR_LOG(RenderingContextXlibLM, PR_LOG_DEBUG, ("nsRenderingContextXlib::GetFontMetrics()\n"));
00720 
00721   aFontMetrics = mFontMetrics;
00722   NS_IF_ADDREF(aFontMetrics);
00723   return NS_OK;
00724 }
00725 
00726 // add the passed in translation to the current translation
00727 NS_IMETHODIMP
00728 nsRenderingContextXlib::Translate(nscoord aX, nscoord aY)
00729 {
00730   PR_LOG(RenderingContextXlibLM, PR_LOG_DEBUG, ("nsRenderingContextXlib::Translate()\n"));
00731   mTranMatrix->AddTranslation((float)aX,(float)aY);
00732   return NS_OK;
00733 }
00734 
00735 // add the passed in scale to the current scale
00736 NS_IMETHODIMP
00737 nsRenderingContextXlib::Scale(float aSx, float aSy)
00738 {
00739   PR_LOG(RenderingContextXlibLM, PR_LOG_DEBUG, ("nsRenderingContextXlib::Scale()\n"));
00740   mTranMatrix->AddScale(aSx, aSy);
00741   return NS_OK;
00742 }
00743 
00744 NS_IMETHODIMP
00745 nsRenderingContextXlib::GetCurrentTransform(nsTransform2D *&aTransform)
00746 {
00747   PR_LOG(RenderingContextXlibLM, PR_LOG_DEBUG, ("nsRenderingContextXlib::GetCurrentTransform()\n"));
00748   aTransform = mTranMatrix;
00749   return NS_OK;
00750 }
00751 
00752 NS_IMETHODIMP
00753 nsRenderingContextXlib::CreateDrawingSurface(const nsRect& aBounds,
00754                                              PRUint32 aSurfFlags,
00755                                              nsIDrawingSurface* &aSurface)
00756 {
00757   PR_LOG(RenderingContextXlibLM, PR_LOG_DEBUG, ("nsRenderingContextXlib::CreateDrawingSurface()\n"));
00758 
00759   if (nsnull == mSurface) {
00760     aSurface = nsnull;
00761     return NS_ERROR_FAILURE;
00762   }
00763 
00764   NS_ENSURE_TRUE((aBounds.width > 0) && (aBounds.height > 0), NS_ERROR_FAILURE);
00765  
00766   nsresult rv = NS_ERROR_FAILURE;
00767   nsDrawingSurfaceXlibImpl *surf = new nsDrawingSurfaceXlibImpl();
00768 
00769   if (surf)
00770   {
00771     NS_ADDREF(surf);
00772     UpdateGC();
00773     rv = surf->Init(mXlibRgbHandle, mGC, aBounds.width, aBounds.height, aSurfFlags);    
00774   }
00775 
00776   aSurface = surf;
00777 
00778   return rv;
00779 }
00780 
00781 NS_IMETHODIMP
00782 nsRenderingContextXlib::DestroyDrawingSurface(nsIDrawingSurface* aDS)
00783 {
00784   PR_LOG(RenderingContextXlibLM, PR_LOG_DEBUG, ("nsRenderingContextXlib::DestroyDrawingSurface()\n"));
00785   nsIDrawingSurfaceXlib *surf = NS_STATIC_CAST(nsIDrawingSurfaceXlib *, aDS);;
00786 
00787   NS_ENSURE_TRUE(surf != nsnull, NS_ERROR_FAILURE);
00788 
00789   NS_IF_RELEASE(surf);
00790 
00791   return NS_OK;
00792 }
00793 
00794 NS_IMETHODIMP
00795 nsRenderingContextXlib::DrawLine(nscoord aX0, nscoord aY0, nscoord aX1, nscoord aY1)
00796 {
00797   PR_LOG(RenderingContextXlibLM, PR_LOG_DEBUG, ("nsRenderingContextXlib::DrawLine()\n"));
00798 
00799   nscoord diffX, diffY;
00800 
00801   NS_ENSURE_TRUE(mTranMatrix != nsnull, NS_ERROR_FAILURE);
00802   NS_ENSURE_TRUE(mSurface    != nsnull, NS_ERROR_FAILURE);
00803 
00804   mTranMatrix->TransformCoord(&aX0,&aY0);
00805   mTranMatrix->TransformCoord(&aX1,&aY1);
00806   
00807   diffX = aX1-aX0;
00808   diffY = aY1-aY0;
00809 
00810   if (0!=diffX) {
00811     diffX = (diffX>0?1:-1);
00812   }
00813   if (0!=diffY) {
00814     diffY = (diffY>0?1:-1);
00815   }
00816 
00817   UpdateGC();
00818   Drawable drawable; mSurface->GetDrawable(drawable);
00819   ::XDrawLine(mDisplay, drawable,
00820               *mGC, aX0, aY0, aX1 - diffX, aY1 - diffY);
00821 
00822   return NS_OK;
00823 }
00824 
00825 NS_IMETHODIMP
00826 nsRenderingContextXlib::DrawPolyline(const nsPoint aPoints[], PRInt32 aNumPoints)
00827 {
00828   PR_LOG(RenderingContextXlibLM, PR_LOG_DEBUG, ("nsRenderingContextXlib::DrawPolyLine()\n"));
00829 
00830   NS_ENSURE_TRUE(mTranMatrix != nsnull, NS_ERROR_FAILURE);
00831   NS_ENSURE_TRUE(mSurface    != nsnull, NS_ERROR_FAILURE);
00832 
00833   PRInt32  i;
00834   XPoint * xpoints;
00835   XPoint * thispoint;
00836 
00837   xpoints = (XPoint *) malloc(sizeof(XPoint) * aNumPoints);
00838   NS_ENSURE_TRUE(xpoints != nsnull, NS_ERROR_OUT_OF_MEMORY);
00839 
00840   for (i = 0; i < aNumPoints; i++){
00841     thispoint = (xpoints+i);
00842     thispoint->x = aPoints[i].x;
00843     thispoint->y = aPoints[i].y;
00844     mTranMatrix->TransformCoord((PRInt32*)&thispoint->x,(PRInt32*)&thispoint->y);
00845   }
00846 
00847   UpdateGC();
00848   Drawable drawable; mSurface->GetDrawable(drawable);
00849   ::XDrawLines(mDisplay,
00850                drawable,
00851                *mGC,
00852                xpoints, aNumPoints, CoordModeOrigin);
00853 
00854   free((void *)xpoints);
00855 
00856   return NS_OK;
00857 }
00858 
00859 NS_IMETHODIMP
00860 nsRenderingContextXlib::DrawRect(const nsRect& aRect)
00861 {
00862   PR_LOG(RenderingContextXlibLM, PR_LOG_DEBUG, ("nsRenderingContextXlib::DrawRext(const nsRect& aRect)\n"));
00863   return DrawRect(aRect.x, aRect.y, aRect.width, aRect.height);
00864 }
00865 
00866 NS_IMETHODIMP
00867 nsRenderingContextXlib::DrawRect(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight)
00868 {
00869   PR_LOG(RenderingContextXlibLM, PR_LOG_DEBUG, ("nsRenderingContextXlib::DrawRect(aX, aY, aWidth, aHeight)\n"));
00870 
00871   NS_ENSURE_TRUE(mTranMatrix != nsnull, NS_ERROR_FAILURE);
00872   NS_ENSURE_TRUE(mSurface    != nsnull, NS_ERROR_FAILURE);
00873 
00874   nscoord x, y, w, h; 
00875   
00876   x = aX;
00877   y = aY; 
00878   w = aWidth;
00879   h = aHeight;
00880     
00881   mTranMatrix->TransformCoord(&x,&y,&w,&h);
00882     
00883   // After the transform, if the numbers are huge, chop them, because
00884   // they're going to be converted from 32 bit to 16 bit.
00885   // It's all way off the screen anyway.
00886   ConditionRect(x,y,w,h);
00887    
00888   // Don't draw empty rectangles; also, w/h are adjusted down by one
00889   // so that the right number of pixels are drawn.
00890   if (w && h) 
00891   {
00892     UpdateGC();
00893     Drawable drawable; mSurface->GetDrawable(drawable);
00894     ::XDrawRectangle(mDisplay,
00895                      drawable,
00896                      *mGC,
00897                      x,
00898                      y,
00899                      w-1,
00900                      h-1);
00901   }
00902 
00903   return NS_OK;
00904 }
00905 
00906 
00907 NS_IMETHODIMP
00908 nsRenderingContextXlib::FillRect(const nsRect& aRect)
00909 {
00910   PR_LOG(RenderingContextXlibLM, PR_LOG_DEBUG, ("nsRenderingContextXlib::FillRect()\n"));
00911   return FillRect(aRect.x, aRect.y, aRect.width, aRect.height);
00912 }
00913 
00914 NS_IMETHODIMP
00915 nsRenderingContextXlib::FillRect(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight)
00916 {
00917   PR_LOG(RenderingContextXlibLM, PR_LOG_DEBUG, ("nsRenderingContextXlib::FillRect()\n"));
00918 
00919   NS_ENSURE_TRUE(mTranMatrix != nsnull, NS_ERROR_FAILURE);
00920   NS_ENSURE_TRUE(mSurface    != nsnull, NS_ERROR_FAILURE);
00921 
00922   nscoord x,y,w,h;
00923   x = aX;
00924   y = aY;
00925   w = aWidth;
00926   h = aHeight;
00927 
00928   mTranMatrix->TransformCoord(&x,&y,&w,&h);
00929 
00930   // After the transform, if the numbers are huge, chop them, because
00931   // they're going to be converted from 32 bit to 16 bit.
00932   // It's all way off the screen anyway.
00933   ConditionRect(x,y,w,h);
00934 
00935   Drawable drawable; mSurface->GetDrawable(drawable);
00936   PR_LOG(RenderingContextXlibLM, PR_LOG_DEBUG, ("About to fill window 0x%lxd with rect %d %d %d %d\n",
00937                                                 drawable, x, y, w, h));
00938   UpdateGC();
00939   ::XFillRectangle(mDisplay,
00940                    drawable,
00941                    *mGC,
00942                    x,y,w,h);
00943   
00944   return NS_OK;
00945 }
00946 
00947 NS_IMETHODIMP
00948 nsRenderingContextXlib::InvertRect(const nsRect& aRect)
00949 {
00950   PR_LOG(RenderingContextXlibLM, PR_LOG_DEBUG, ("nsRenderingContextXlib::InvertRect()\n"));
00951   return InvertRect(aRect.x, aRect.y, aRect.width, aRect.height);
00952 }
00953 
00954 NS_IMETHODIMP 
00955 nsRenderingContextXlib::InvertRect(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight)
00956 {
00957   PR_LOG(RenderingContextXlibLM, PR_LOG_DEBUG, ("nsRenderingContextXlib::InvertRect()\n"));
00958 
00959   NS_ENSURE_TRUE(mTranMatrix != nsnull, NS_ERROR_FAILURE);
00960   NS_ENSURE_TRUE(mSurface    != nsnull, NS_ERROR_FAILURE);
00961   
00962   // Back up the current color, and use GXxor against white to get a
00963   // visible result.
00964   nscolor backupColor = mCurrentColor;
00965   mCurrentColor = NS_RGB(255, 255, 255);
00966   nscoord x,y,w,h;
00967 
00968   x = aX;
00969   y = aY;
00970   w = aWidth;
00971   h = aHeight;
00972 
00973   mTranMatrix->TransformCoord(&x,&y,&w,&h);
00974 
00975   // After the transform, if the numbers are huge, chop them, because
00976   // they're going to be converted from 32 bit to 16 bit.
00977   // It's all way off the screen anyway.
00978   ConditionRect(x,y,w,h);
00979 
00980   mFunction = GXxor;
00981   
00982   UpdateGC();
00983   Drawable drawable; mSurface->GetDrawable(drawable);
00984   ::XFillRectangle(mDisplay,
00985                    drawable,
00986                    *mGC,
00987                    x,
00988                    y,
00989                    w,
00990                    h);
00991   
00992   mFunction = GXcopy;
00993 
00994   // Restore current color
00995   mCurrentColor = backupColor;
00996 
00997   return NS_OK;
00998 }
00999 
01000 NS_IMETHODIMP
01001 nsRenderingContextXlib::DrawPolygon(const nsPoint aPoints[], PRInt32 aNumPoints)
01002 {
01003   PR_LOG(RenderingContextXlibLM, PR_LOG_DEBUG, ("nsRenderingContextXlib::DrawPolygon()\n"));
01004 
01005   NS_ENSURE_TRUE(mTranMatrix != nsnull, NS_ERROR_FAILURE);
01006   NS_ENSURE_TRUE(mSurface    != nsnull, NS_ERROR_FAILURE);
01007 
01008   PRInt32 i ;
01009   XPoint * xpoints;
01010   XPoint * thispoint;
01011   
01012   xpoints = (XPoint *) malloc(sizeof(XPoint) * aNumPoints);
01013   NS_ENSURE_TRUE(xpoints != nsnull, NS_ERROR_OUT_OF_MEMORY);
01014   
01015   for (i = 0; i < aNumPoints; i++){
01016     thispoint = (xpoints+i);
01017     thispoint->x = aPoints[i].x;
01018     thispoint->y = aPoints[i].y;
01019     mTranMatrix->TransformCoord((PRInt32*)&thispoint->x,(PRInt32*)&thispoint->y);
01020   }
01021   
01022   UpdateGC();
01023   Drawable drawable; mSurface->GetDrawable(drawable);
01024   ::XDrawLines(mDisplay,
01025                drawable,
01026                *mGC,
01027                xpoints, aNumPoints, CoordModeOrigin);
01028 
01029   free((void *)xpoints);
01030   
01031   return NS_OK;    
01032 }
01033 
01034 NS_IMETHODIMP
01035 nsRenderingContextXlib::FillPolygon(const nsPoint aPoints[], PRInt32 aNumPoints)
01036 {
01037   PR_LOG(RenderingContextXlibLM, PR_LOG_DEBUG, ("nsRenderingContextXlib::FillPolygon()\n"));
01038 
01039   NS_ENSURE_TRUE(mTranMatrix != nsnull, NS_ERROR_FAILURE);
01040   NS_ENSURE_TRUE(mSurface    != nsnull, NS_ERROR_FAILURE);
01041 
01042   PRInt32 i ;
01043   XPoint * xpoints;
01044    
01045   xpoints = (XPoint *) malloc(sizeof(XPoint) * aNumPoints);
01046   NS_ENSURE_TRUE(xpoints != nsnull, NS_ERROR_OUT_OF_MEMORY);
01047   
01048   for (i = 0; i < aNumPoints; ++i) {
01049     nsPoint p = aPoints[i];
01050     mTranMatrix->TransformCoord(&p.x, &p.y);
01051     xpoints[i].x = p.x;
01052     xpoints[i].y = p.y;
01053   } 
01054     
01055   UpdateGC();
01056   Drawable drawable; mSurface->GetDrawable(drawable);
01057   ::XFillPolygon(mDisplay,
01058                  drawable,
01059                  *mGC,
01060                  xpoints, aNumPoints, Complex, CoordModeOrigin);
01061                
01062   free((void *)xpoints);
01063 
01064   return NS_OK; 
01065 }
01066 
01067 NS_IMETHODIMP
01068 nsRenderingContextXlib::DrawEllipse(const nsRect& aRect)
01069 {
01070   PR_LOG(RenderingContextXlibLM, PR_LOG_DEBUG, ("nsRenderingContextXlib::DrawEllipse(const nsRect& aRect)\n"));
01071   return DrawEllipse(aRect.x, aRect.y, aRect.width, aRect.height);
01072 }
01073 
01074 NS_IMETHODIMP
01075 nsRenderingContextXlib::DrawEllipse(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight)
01076 {
01077   PR_LOG(RenderingContextXlibLM, PR_LOG_DEBUG, ("nsRenderingContextXlib::DrawEllipse(aX, aY, aWidth, aHeight)\n"));
01078 
01079   NS_ENSURE_TRUE(mTranMatrix != nsnull, NS_ERROR_FAILURE);
01080   NS_ENSURE_TRUE(mSurface    != nsnull, NS_ERROR_FAILURE);
01081 
01082   nscoord x, y, w, h;
01083    
01084   x = aX; 
01085   y = aY;
01086   w = aWidth; 
01087   h = aHeight;
01088     
01089   mTranMatrix->TransformCoord(&x,&y,&w,&h);
01090     
01091   UpdateGC();
01092   Drawable drawable; mSurface->GetDrawable(drawable);
01093   ::XDrawArc(mDisplay,
01094              drawable,
01095              *mGC,
01096              x, y, w, h, 0, 360*64);
01097   
01098   return NS_OK;  
01099 }
01100 
01101 NS_IMETHODIMP
01102 nsRenderingContextXlib::FillEllipse(const nsRect& aRect)
01103 {
01104   PR_LOG(RenderingContextXlibLM, PR_LOG_DEBUG, ("nsRenderingContextXlib::FillEllipse()\n"));
01105   return FillEllipse(aRect.x, aRect.y, aRect.width, aRect.height);
01106 }
01107 
01108 NS_IMETHODIMP
01109 nsRenderingContextXlib::FillEllipse(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight)
01110 {
01111   PR_LOG(RenderingContextXlibLM, PR_LOG_DEBUG, ("nsRenderingContextXlib::FillEllipse()\n"));
01112 
01113   NS_ENSURE_TRUE(mTranMatrix != nsnull, NS_ERROR_FAILURE);
01114   NS_ENSURE_TRUE(mSurface    != nsnull, NS_ERROR_FAILURE);
01115 
01116   nscoord x,y,w,h;
01117    
01118   x = aX; 
01119   y = aY;
01120   w = aWidth; 
01121   h = aHeight;
01122     
01123   mTranMatrix->TransformCoord(&x,&y,&w,&h);
01124     
01125   UpdateGC();
01126   Drawable drawable; mSurface->GetDrawable(drawable);
01127   if (w < 16 || h < 16) {
01128     /* Fix for bug 91816 ("bullets are not displayed correctly on certain text zooms")
01129      * De-uglify bullets on some X servers:
01130      * 1st: Draw... */
01131     ::XDrawArc(mDisplay,
01132                drawable,
01133                *mGC,
01134                x, y, w, h, 0, 360*64);
01135     /*  ...then fill. */
01136   }
01137   ::XFillArc(mDisplay,
01138              drawable,
01139              *mGC,
01140              x, y, w, h, 0, 360*64);
01141   
01142   return NS_OK;  
01143 }
01144 
01145 NS_IMETHODIMP
01146 nsRenderingContextXlib::DrawArc(const nsRect& aRect,
01147                                 float aStartAngle, float aEndAngle)
01148 {
01149   PR_LOG(RenderingContextXlibLM, PR_LOG_DEBUG, ("nsRenderingContextXlib::DrawArc()\n"));
01150   return DrawArc(aRect.x,aRect.y,aRect.width,aRect.height,aStartAngle,aEndAngle); 
01151 }
01152 
01153 NS_IMETHODIMP
01154 nsRenderingContextXlib::DrawArc(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight,
01155                                 float aStartAngle, float aEndAngle)
01156 {
01157   PR_LOG(RenderingContextXlibLM, PR_LOG_DEBUG, ("nsRenderingContextXlib::DrawArc()\n"));
01158 
01159   NS_ENSURE_TRUE(mTranMatrix != nsnull, NS_ERROR_FAILURE);
01160   NS_ENSURE_TRUE(mSurface    != nsnull, NS_ERROR_FAILURE);
01161 
01162   nscoord x, y, w, h;
01163    
01164   x = aX; 
01165   y = aY;
01166   w = aWidth; 
01167   h = aHeight;
01168     
01169   mTranMatrix->TransformCoord(&x,&y,&w,&h);
01170     
01171   UpdateGC();
01172   Drawable drawable; mSurface->GetDrawable(drawable);
01173   ::XDrawArc(mDisplay,
01174              drawable,
01175              *mGC,
01176              x,y,w,h, NSToIntRound(aStartAngle * 64.0f),
01177              NSToIntRound(aEndAngle * 64.0f));
01178   
01179   return NS_OK;  
01180 }
01181 
01182 NS_IMETHODIMP
01183 nsRenderingContextXlib::FillArc(const nsRect& aRect,
01184                                 float aStartAngle, float aEndAngle)
01185 {
01186   PR_LOG(RenderingContextXlibLM, PR_LOG_DEBUG, ("nsRenderingContextXlib::FillArc()\n"));
01187   return FillArc(aRect.x, aRect.y, aRect.width, aRect.height, aStartAngle, aEndAngle);
01188 }
01189 
01190 NS_IMETHODIMP
01191 nsRenderingContextXlib::FillArc(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight,
01192                                 float aStartAngle, float aEndAngle)
01193 {
01194   PR_LOG(RenderingContextXlibLM, PR_LOG_DEBUG, ("nsRenderingContextXlib::FillArc()\n"));
01195 
01196   NS_ENSURE_TRUE(mTranMatrix != nsnull, NS_ERROR_FAILURE);
01197   NS_ENSURE_TRUE(mSurface    != nsnull, NS_ERROR_FAILURE);
01198 
01199   nscoord x,y,w,h;
01200    
01201   x = aX; 
01202   y = aY;
01203   w = aWidth; 
01204   h = aHeight;
01205     
01206   mTranMatrix->TransformCoord(&x,&y,&w,&h);
01207     
01208   UpdateGC();
01209   Drawable drawable; mSurface->GetDrawable(drawable);
01210   ::XFillArc(mDisplay,
01211              drawable,
01212              *mGC,
01213              x,y,w,h, NSToIntRound(aStartAngle * 64.0f),
01214              NSToIntRound(aEndAngle * 64.0f));
01215   
01216   return NS_OK;  
01217 }
01218 
01219 // do the 8 to 16 bit conversion on the stack
01220 // if the data is less than this size
01221 #define WIDEN_8_TO_16_BUF_SIZE (1024)
01222 
01223 // handle 8 bit data with a 16 bit font
01224 static
01225 int Widen8To16AndMove(const char *char_p, 
01226                       int char_len, 
01227                       XChar2b *xchar2b_p)
01228 {
01229   int i;
01230   for (i=0; i<char_len; i++) {
01231     (xchar2b_p)->byte1 = 0;
01232     (xchar2b_p++)->byte2 = *char_p++;
01233   }
01234   return(char_len*2);
01235 }
01236 
01237 // handle 8 bit data with a 16 bit font
01238 static
01239 int Widen8To16AndGetWidth(nsXFont    *xFont,
01240                           const char *text,
01241                           int         text_length)
01242 {
01243   NS_ASSERTION(!xFont->IsSingleByte(), "Widen8To16AndGetWidth: wrong string/font size");
01244   XChar2b  buf[WIDEN_8_TO_16_BUF_SIZE];
01245   XChar2b *p = buf;
01246   int uchar_size;
01247   int rawWidth;
01248 
01249   if (text_length > WIDEN_8_TO_16_BUF_SIZE) {
01250     p = (XChar2b*)malloc(text_length*sizeof(XChar2b));
01251     if (!p)
01252       return(0); // handle malloc failure
01253   }
01254 
01255   uchar_size = Widen8To16AndMove(text, text_length, p);
01256   rawWidth = xFont->TextWidth16(p, uchar_size/2);
01257 
01258   if (text_length > WIDEN_8_TO_16_BUF_SIZE) {
01259     free((char*)p);
01260   }
01261   return(rawWidth);
01262 }
01263 
01264 static 
01265 void Widen8To16AndDraw(Drawable     drawable,
01266                        nsXFont     *xFont,
01267                        GC           gc,
01268                        int          x,
01269                        int          y,
01270                        const char  *text,
01271                        int          text_length)
01272 {
01273   NS_ASSERTION(!xFont->IsSingleByte(), "Widen8To16AndDraw: wrong string/font size");
01274   XChar2b buf[WIDEN_8_TO_16_BUF_SIZE];
01275   XChar2b *p = buf;
01276   int uchar_size;
01277 
01278   if (text_length > WIDEN_8_TO_16_BUF_SIZE) {
01279     p = (XChar2b*)malloc(text_length*sizeof(XChar2b));
01280     if (!p)
01281       return; // handle malloc failure
01282   }
01283 
01284   uchar_size = Widen8To16AndMove(text, text_length, p);
01285   xFont->DrawText16(drawable, gc, x, y, p, uchar_size/2);
01286 
01287   if (text_length > WIDEN_8_TO_16_BUF_SIZE) {
01288     free((char*)p);
01289   }
01290 }
01291 
01292 NS_IMETHODIMP
01293 nsRenderingContextXlib::GetWidth(char aC, nscoord &aWidth)
01294 {
01295   // Check for the very common case of trying to get the width of a single
01296   // space.
01297   if ((aC == ' ') && (nsnull != mFontMetrics)) {
01298     return mFontMetrics->GetSpaceWidth(aWidth);
01299   }
01300   return GetWidth(&aC, 1, aWidth);
01301 }
01302 
01303 NS_IMETHODIMP
01304 nsRenderingContextXlib::GetWidth(PRUnichar aC, nscoord& aWidth,
01305                                 PRInt32* aFontID)
01306 {
01307   return GetWidth(&aC, 1, aWidth, aFontID);
01308 }
01309 
01310 NS_IMETHODIMP
01311 nsRenderingContextXlib::GetWidth(const nsString& aString,
01312                                  nscoord& aWidth, PRInt32* aFontID)
01313 {
01314   return GetWidth(aString.get(), aString.Length(), aWidth, aFontID);
01315 }
01316 
01317 NS_IMETHODIMP
01318 nsRenderingContextXlib::GetWidth(const char* aString, nscoord& aWidth)
01319 {
01320   return GetWidth(aString, strlen(aString), aWidth);
01321 }
01322 
01323 NS_IMETHODIMP
01324 nsRenderingContextXlib::GetWidth(const char* aString, PRUint32 aLength,
01325                                  nscoord& aWidth)
01326 {
01327   if (0 == aLength) {
01328     aWidth = 0;
01329   }
01330   else {
01331     NS_ENSURE_TRUE(aString      != nsnull, NS_ERROR_FAILURE);
01332     NS_ENSURE_TRUE(mCurrentFont != nsnull, NS_ERROR_FAILURE);
01333     int rawWidth;
01334     nsXFont *xFont = mCurrentFont->GetXFont();
01335 #ifdef USE_FREETYPE
01336     if (mCurrentFont->IsFreeTypeFont()) {
01337       // this function is only supposed to be called for ascii data
01338       rawWidth = mCurrentFont->
01339         GetWidth(NS_ConvertASCIItoUTF16(aString, aLength).get(), aLength);
01340     }
01341     else
01342 #endif /* USE_FREETYPE */
01343     if (!mCurrentFont->GetXFontIs10646()) {
01344       NS_ASSERTION(xFont->IsSingleByte(), "wrong string/font size");
01345       // 8 bit data with an 8 bit font
01346       rawWidth = xFont->TextWidth8(aString, aLength);
01347     }
01348     else {
01349       NS_ASSERTION(!xFont->IsSingleByte(), "wrong string/font size");
01350       // we have 8 bit data but a 16 bit font
01351       rawWidth = Widen8To16AndGetWidth (mCurrentFont->GetXFont(), aString, aLength);
01352     }
01353     aWidth = NSToCoordRound(rawWidth * mP2T);
01354   }
01355   return NS_OK;
01356 }
01357 
01358 NS_IMETHODIMP
01359 nsRenderingContextXlib::GetWidth(const PRUnichar* aString, PRUint32 aLength,
01360                                  nscoord& aWidth, PRInt32* aFontID)
01361 {
01362   if (0 == aLength) {
01363     aWidth = 0;
01364   }
01365   else {
01366     NS_ENSURE_TRUE(aString != nsnull, NS_ERROR_FAILURE);
01367 
01368     nsFontMetricsXlib *metrics = NS_REINTERPRET_CAST(nsFontMetricsXlib *, mFontMetrics.get());
01369 
01370     NS_ENSURE_TRUE(metrics != nsnull, NS_ERROR_FAILURE);
01371 
01372     nsFontXlib *prevFont = nsnull;
01373     int rawWidth = 0;
01374     PRUint32 start = 0;
01375     PRUint32 i;
01376     for (i = 0; i < aLength; i++) {
01377       PRUnichar c = aString[i];
01378       nsFontXlib  *currFont = nsnull;
01379       nsFontXlib **font = metrics->mLoadedFonts;
01380       nsFontXlib **end = &metrics->mLoadedFonts[metrics->mLoadedFontsCount];
01381       while (font < end) {
01382         if (CCMAP_HAS_CHAR((*font)->mCCMap, c)) {
01383           currFont = *font;
01384           goto FoundFont; // for speed -- avoid "if" statement
01385         }
01386         font++;
01387       }
01388       currFont = metrics->FindFont(c);
01389 FoundFont:
01390       // XXX avoid this test by duplicating code -- erik
01391       if (prevFont) {
01392         if (currFont != prevFont) {
01393           rawWidth += prevFont->GetWidth(&aString[start], i - start);
01394           prevFont = currFont;
01395           start = i;
01396         }
01397       }
01398       else {
01399         prevFont = currFont;
01400         start = i;
01401       }
01402     }
01403 
01404     if (prevFont) {
01405       rawWidth += prevFont->GetWidth(&aString[start], i - start);
01406     }
01407 
01408     aWidth = NSToCoordRound(rawWidth * mP2T);
01409   }
01410   if (nsnull != aFontID)
01411     *aFontID = 0;
01412 
01413   return NS_OK;
01414 }
01415 
01416 NS_IMETHODIMP
01417 nsRenderingContextXlib::GetTextDimensions(const char*       aString,
01418                                           PRInt32           aLength,
01419                                           PRInt32           aAvailWidth,
01420                                           PRInt32*          aBreaks,
01421                                           PRInt32           aNumBreaks,
01422                                           nsTextDimensions& aDimensions,
01423                                           PRInt32&          aNumCharsFit,
01424                                           nsTextDimensions& aLastWordDimensions,
01425                                           PRInt32*          aFontID)
01426 {
01427   NS_PRECONDITION(aBreaks[aNumBreaks - 1] == aLength, "invalid break array");
01428 
01429   if (nsnull != mFontMetrics) {
01430     // If we need to back up this state represents the last place we could
01431     // break. We can use this to avoid remeasuring text
01432     PRInt32 prevBreakState_BreakIndex = -1; // not known (hasn't been computed)
01433     nscoord prevBreakState_Width = 0; // accumulated width to this point
01434 
01435     // Initialize OUT parameters
01436     mFontMetrics->GetMaxAscent(aLastWordDimensions.ascent);
01437     mFontMetrics->GetMaxDescent(aLastWordDimensions.descent);
01438     aLastWordDimensions.width = -1;
01439     aNumCharsFit = 0;
01440 
01441     // Iterate each character in the string and determine which font to use
01442     nscoord width = 0;
01443     PRInt32 start = 0;
01444     nscoord aveCharWidth;
01445     mFontMetrics->GetAveCharWidth(aveCharWidth);
01446 
01447     while (start < aLength) {
01448       // Estimate how many characters will fit. Do that by diving the available
01449       // space by the average character width. Make sure the estimated number
01450       // of characters is at least 1
01451       PRInt32 estimatedNumChars = 0;
01452       if (aveCharWidth > 0) {
01453         estimatedNumChars = (aAvailWidth - width) / aveCharWidth;
01454       }
01455       if (estimatedNumChars < 1) {
01456         estimatedNumChars = 1;
01457       }
01458 
01459       // Find the nearest break offset
01460       PRInt32 estimatedBreakOffset = start + estimatedNumChars;
01461       PRInt32 breakIndex;
01462       nscoord numChars;
01463 
01464       // Find the nearest place to break that is less than or equal to
01465       // the estimated break offset
01466       if (aLength <= estimatedBreakOffset) {
01467         // All the characters should fit
01468         numChars = aLength - start;
01469         breakIndex = aNumBreaks - 1;
01470       } 
01471       else {
01472         breakIndex = prevBreakState_BreakIndex;
01473         while (((breakIndex + 1) < aNumBreaks) &&
01474                (aBreaks[breakIndex + 1] <= estimatedBreakOffset)) {
01475           ++breakIndex;
01476         }
01477         if (breakIndex == prevBreakState_BreakIndex) {
01478           ++breakIndex; // make sure we advanced past the previous break index
01479         }
01480         numChars = aBreaks[breakIndex] - start;
01481       }
01482 
01483       // Measure the text
01484       nscoord twWidth = 0;
01485       if ((1 == numChars) && (aString[start] == ' ')) {
01486         mFontMetrics->GetSpaceWidth(twWidth);
01487       } 
01488       else if (numChars > 0)
01489         GetWidth( &aString[start], numChars, twWidth);
01490 
01491       // See if the text fits
01492       PRBool  textFits = (twWidth + width) <= aAvailWidth;
01493 
01494       // If the text fits then update the width and the number of
01495       // characters that fit
01496       if (textFits) {
01497         aNumCharsFit += numChars;
01498         width += twWidth;
01499         start += numChars;
01500 
01501         // This is a good spot to back up to if we need to so remember
01502         // this state
01503         prevBreakState_BreakIndex = breakIndex;
01504         prevBreakState_Width = width;
01505       }
01506       else {
01507         // See if we can just back up to the previous saved state and not
01508         // have to measure any text
01509         if (prevBreakState_BreakIndex > 0) {
01510           // If the previous break index is just before the current break index
01511           // then we can use it
01512           if (prevBreakState_BreakIndex == (breakIndex - 1)) {
01513             aNumCharsFit = aBreaks[prevBreakState_BreakIndex];
01514             width = prevBreakState_Width;
01515             break;
01516           }
01517         }
01518 
01519         // We can't just revert to the previous break state
01520         if (0 == breakIndex) {
01521           // There's no place to back up to, so even though the text doesn't fit
01522           // return it anyway
01523           aNumCharsFit += numChars;
01524           width += twWidth;
01525           break;
01526         }
01527 
01528         // Repeatedly back up until we get to where the text fits or we're all
01529         // the way back to the first word
01530         width += twWidth;
01531         while ((breakIndex >= 1) && (width > aAvailWidth)) {
01532           twWidth = 0;
01533           start = aBreaks[breakIndex - 1];
01534           numChars = aBreaks[breakIndex] - start;
01535           
01536           if ((1 == numChars) && (aString[start] == ' ')) {
01537             mFontMetrics->GetSpaceWidth(twWidth);
01538           } 
01539           else if (numChars > 0)
01540             GetWidth( &aString[start], numChars, twWidth);
01541 
01542           width -= twWidth;
01543           aNumCharsFit = start;
01544           breakIndex--;
01545         }
01546         break;
01547       }
01548     }
01549 
01550     aDimensions.width = width;
01551     mFontMetrics->GetMaxAscent(aDimensions.ascent);
01552     mFontMetrics->GetMaxDescent(aDimensions.descent);
01553 
01554     return NS_OK;
01555   }
01556 
01557   return NS_ERROR_FAILURE;
01558 }
01559 
01560 struct BreakGetTextDimensionsData {
01561   float    mP2T;               // IN
01562   PRInt32  mAvailWidth;        // IN
01563   PRInt32* mBreaks;            // IN
01564   PRInt32  mNumBreaks;         // IN
01565   nscoord  mSpaceWidth;        // IN
01566   nscoord  mAveCharWidth;      // IN
01567   PRInt32  mEstimatedNumChars; // IN (running -- to handle the edge case of one word)
01568 
01569   PRInt32  mNumCharsFit;  // IN/OUT -- accumulated number of chars that fit so far
01570   nscoord  mWidth;        // IN/OUT -- accumulated width so far
01571 
01572   // If we need to back up, this state represents the last place
01573   // we could break. We can use this to avoid remeasuring text
01574   PRInt32 mPrevBreakState_BreakIndex; // IN/OUT, initialized as -1, i.e., not yet computed
01575   nscoord mPrevBreakState_Width;      // IN/OUT, initialized as  0
01576 
01577   // Remember the fonts that we use so that we can deal with
01578   // line-breaking in-between fonts later. mOffsets[0] is also used
01579   // to initialize the current offset from where to start measuring
01580   nsVoidArray* mFonts;   // IN/OUT
01581   nsVoidArray* mOffsets; // IN/OUT
01582 };
01583 
01584 static PRBool PR_CALLBACK
01585 do_BreakGetTextDimensions(const nsFontSwitchXlib *aFontSwitch,
01586                           const PRUnichar*        aSubstring,
01587                           PRUint32                aSubstringLength,
01588                           void*                   aData)
01589 {
01590   nsFontXlib *fontXlib = aFontSwitch->mFontXlib;
01591 
01592   // Make sure the font is selected
01593   BreakGetTextDimensionsData* data = (BreakGetTextDimensionsData*)aData;
01594 
01595   // Our current state relative to the _full_ string...
01596   // This allows emulation of the previous code...
01597   const PRUnichar* pstr = (const PRUnichar*)data->mOffsets->ElementAt(0);
01598   PRInt32 numCharsFit = data->mNumCharsFit;
01599   nscoord width = data->mWidth;
01600   PRInt32 start = (PRInt32)(aSubstring - pstr);
01601   PRInt32 end = start + aSubstringLength;
01602   PRBool allDone = PR_FALSE;
01603 
01604   while (start < end) {
01605     // Estimate how many characters will fit. Do that by dividing the
01606     // available space by the average character width
01607     PRInt32 estimatedNumChars = data->mEstimatedNumChars;
01608     if (!estimatedNumChars && data->mAveCharWidth > 0) {
01609       estimatedNumChars = (data->mAvailWidth - width) / data->mAveCharWidth;
01610     }
01611     // Make sure the estimated number of characters is at least 1
01612     if (estimatedNumChars < 1) {
01613       estimatedNumChars = 1;
01614     }
01615 
01616     // Find the nearest break offset
01617     PRInt32 estimatedBreakOffset = start + estimatedNumChars;
01618     PRInt32 breakIndex = -1; // not yet computed
01619     PRBool  inMiddleOfSegment = PR_FALSE;
01620     nscoord numChars;
01621 
01622     // Avoid scanning the break array in the case where we think all
01623     // the text should fit
01624     if (end <= estimatedBreakOffset) {
01625       // Everything should fit
01626       numChars = end - start;
01627     }
01628     else {
01629       // Find the nearest place to break that is less than or equal to
01630       // the estimated break offset
01631       breakIndex = data->mPrevBreakState_BreakIndex;
01632       while (breakIndex + 1 < data->mNumBreaks &&
01633              data->mBreaks[breakIndex + 1] <= estimatedBreakOffset) {
01634         ++breakIndex;
01635       }
01636 
01637       if (breakIndex == -1)
01638         breakIndex = 0;
01639 
01640       // We found a place to break that is before the estimated break
01641       // offset. Where we break depends on whether the text crosses a
01642       // segment boundary
01643       if (start < data->mBreaks[breakIndex]) {
01644         // The text crosses at least one segment boundary so measure to the
01645         // break point just before the estimated break offset
01646         numChars = PR_MIN(data->mBreaks[breakIndex], end) - start;
01647       } 
01648       else {
01649         // See whether there is another segment boundary between this one
01650         // and the end of the text
01651         if ((breakIndex < (data->mNumBreaks - 1)) && (data->mBreaks[breakIndex] < end)) {
01652           ++breakIndex;
01653           numChars = PR_MIN(data->mBreaks[breakIndex], end) - start;
01654         }
01655         else {
01656           NS_ASSERTION(end != data->mBreaks[breakIndex], "don't expect to be at segment boundary");
01657 
01658           // The text is all within the same segment
01659           numChars = end - start;
01660 
01661           // Remember we're in the middle of a segment and not between
01662           // two segments
01663           inMiddleOfSegment = PR_TRUE;
01664         }
01665       }
01666     }
01667 
01668     // Measure the text
01669     nscoord twWidth, pxWidth;
01670     if ((1 == numChars) && (pstr[start] == ' ')) {
01671       twWidth = data->mSpaceWidth;
01672     }
01673     else {
01674       pxWidth = fontXlib->GetWidth(&pstr[start], numChars);
01675       twWidth = NSToCoordRound(float(pxWidth) * data->mP2T);
01676     }
01677 
01678     // See if the text fits
01679     PRBool textFits = (twWidth + width) <= data->mAvailWidth;
01680 
01681     // If the text fits then update the width and the number of
01682     // characters that fit
01683     if (textFits) {
01684       numCharsFit += numChars;
01685       width += twWidth;
01686 
01687       // If we computed the break index and we're not in the middle
01688       // of a segment then this is a spot that we can back up to if
01689       // we need to, so remember this state
01690       if ((breakIndex != -1) && !inMiddleOfSegment) {
01691         data->mPrevBreakState_BreakIndex = breakIndex;
01692         data->mPrevBreakState_Width = width;
01693       }
01694     }
01695     else {
01696       // The text didn't fit. If we're out of room then we're all done
01697       allDone = PR_TRUE;
01698 
01699       // See if we can just back up to the previous saved state and not
01700       // have to measure any text
01701       if (data->mPrevBreakState_BreakIndex != -1) {
01702         PRBool canBackup;
01703 
01704         // If we're in the middle of a word then the break index
01705         // must be the same if we can use it. If we're at a segment
01706         // boundary, then if the saved state is for the previous
01707         // break index then we can use it
01708         if (inMiddleOfSegment) {
01709           canBackup = data->mPrevBreakState_BreakIndex == breakIndex;
01710         } else {
01711           canBackup = data->mPrevBreakState_BreakIndex == (breakIndex - 1);
01712         }
01713 
01714         if (canBackup) {
01715           numCharsFit = data->mBreaks[data->mPrevBreakState_BreakIndex];
01716           width = data->mPrevBreakState_Width;
01717           break;
01718         }
01719       }
01720 
01721       // We can't just revert to the previous break state. Find the break
01722       // index just before the end of the text
01723       end = start + numChars;
01724       breakIndex = 0;
01725       if (data->mBreaks[breakIndex] < end) {
01726         while ((breakIndex + 1 < data->mNumBreaks) && (data->mBreaks[breakIndex + 1] < end)) {
01727           ++breakIndex;
01728         }
01729       }
01730 
01731       if ((0 == breakIndex) && (end <= data->mBreaks[0])) {
01732         // There's no place to back up to, so even though the text doesn't fit
01733         // return it anyway
01734         numCharsFit += numChars;
01735         width += twWidth;
01736 
01737         // Edge case of one word: it could be that we just measured a fragment of the
01738         // first word and its remainder involves other fonts, so we want to keep going
01739         // until we at least measure the entire first word
01740         if (numCharsFit < data->mBreaks[0]) {
01741           allDone = PR_FALSE;
01742           // From now on we don't care anymore what is the _real_ estimated
01743           // number of characters that fits. Rather, we have no where to break
01744           // and have to measure one word fully, but the real estimate is less
01745           // than that one word. However, since the other bits of code rely on
01746           // what is in "data->mEstimatedNumChars", we want to override
01747           // "data->mEstimatedNumChars" and pass in what _has_ to be measured
01748           // so that it is transparent to the other bits that depend on it.
01749           data->mEstimatedNumChars = data->mBreaks[0] - numCharsFit;
01750           start += numChars;
01751         }
01752 
01753         break;
01754       }
01755 
01756       // Repeatedly back up until we get to where the text fits or we're
01757       // all the way back to the first word
01758       width += twWidth;
01759       while ((breakIndex >= 0) && (width > data->mAvailWidth)) {
01760         start = data->mBreaks[breakIndex];
01761         numChars = end - start;
01762         numCharsFit = start;
01763         if ((1 == numChars) && (pstr[start] == ' ')) {
01764           width -= data->mSpaceWidth;
01765         }
01766         else if (pstr + start >= aSubstring) {
01767           // The entire fragment to chop is within the current font.
01768           pxWidth = fontXlib->GetWidth(&pstr[start], numChars);
01769           width -= NSToCoordRound(float(pxWidth) * data->mP2T);
01770         }
01771         else {
01772           // The fragment that we want to chop extends back into previous fonts.
01773           // We need to reverse into previous fonts. Fortunately,
01774           // data->mFonts[] and data->mOffsets[] tell us which fonts are used
01775           // and when. 
01776           end = data->mNumCharsFit; // same as aSubstring - pstr
01777           data->mNumCharsFit = numCharsFit; // has got shorter...
01778           PRInt32 k = data->mFonts->Count() - 1;
01779           for ( ; k >= 0 && start < end; --k, end -= numChars) {
01780             fontXlib = (nsFontXlib*)data->mFonts->ElementAt(k);
01781             const PRUnichar* ps = (const PRUnichar*)data->mOffsets->ElementAt(k);
01782             if (ps < pstr + start)
01783               ps = pstr + start;
01784 
01785             numChars = pstr + end - ps;
01786             NS_ASSERTION(numChars > 0, "empty string");
01787 
01788             pxWidth = fontXlib->GetWidth(ps, numChars);
01789             data->mWidth -= NSToCoordRound(float(pxWidth) * data->mP2T);
01790 
01791             // By construction, mFonts[k] is the last font, and
01792             // mOffsets[k+1] is the last offset.
01793             data->mFonts->RemoveElementAt(k);
01794             data->mOffsets->RemoveElementAt(k+1);
01795           }
01796 
01797           // We are done, update the data now because we won't do it later.
01798           // The |if (data->mNumCharsFit != numCharsFit)| won't apply below
01799           data->mFonts->AppendElement(fontXlib);
01800           data->mOffsets->AppendElement((void*)&pstr[numCharsFit]);
01801           break;
01802         }
01803 
01804         --breakIndex;
01805         end = start;
01806       }
01807     }
01808 
01809     start += numChars;
01810   }
01811 
01812 #ifdef DEBUG_rbs
01813   NS_ASSERTION(allDone || start == end, "internal error");
01814   NS_ASSERTION(allDone || data->mNumCharsFit != numCharsFit, "internal error");
01815 #endif /* DEBUG_rbs */
01816 
01817   if (data->mNumCharsFit != numCharsFit) {
01818     // some text was actually retained
01819     data->mWidth = width;
01820     data->mNumCharsFit = numCharsFit;
01821     data->mFonts->AppendElement(fontXlib);
01822     data->mOffsets->AppendElement((void*)&pstr[numCharsFit]);
01823   }
01824 
01825   if (allDone) {
01826     // stop now
01827     return PR_FALSE;
01828   }
01829 
01830   return PR_TRUE; // don't stop if we still need to measure more characters
01831 }
01832 
01833 NS_IMETHODIMP
01834 nsRenderingContextXlib::GetTextDimensions(const PRUnichar*  aString,
01835                                           PRInt32           aLength,
01836                                           PRInt32           aAvailWidth,
01837                                           PRInt32*          aBreaks,
01838                                           PRInt32           aNumBreaks,
01839                                           nsTextDimensions& aDimensions,
01840                                           PRInt32&          aNumCharsFit,
01841                                           nsTextDimensions& aLastWordDimensions,
01842                                           PRInt32*          aFontID)
01843 {
01844   if (!mFontMetrics)
01845     return NS_ERROR_FAILURE;
01846 
01847   nsFontMetricsXlib *metrics = NS_REINTERPRET_CAST(nsFontMetricsXlib *, mFontMetrics.get());
01848 
01849   nscoord spaceWidth, aveCharWidth;
01850   metrics->GetSpaceWidth(spaceWidth);
01851   metrics->GetAveCharWidth(aveCharWidth);
01852 
01853   // Note: aBreaks[] is supplied to us so that the first word is located
01854   // at aString[0 .. aBreaks[0]-1] and more generally, the k-th word is
01855   // located at aString[aBreaks[k-1] .. aBreaks[k]-1]. Whitespace can
01856   // be included and each of them counts as a word in its own right.
01857 
01858   // Upon completion of glyph resolution, characters that can be
01859   // represented with fonts[i] are at offsets[i] .. offsets[i+1]-1
01860 
01861   nsAutoVoidArray fonts, offsets;
01862   offsets.AppendElement((void*)aString);
01863 
01864   BreakGetTextDimensionsData data = { mP2T, aAvailWidth, aBreaks, aNumBreaks,
01865     spaceWidth, aveCharWidth, 0, 0, 0, -1, 0, &fonts, &offsets 
01866   };
01867 
01868   metrics->ResolveForwards(aString, aLength, do_BreakGetTextDimensions, &data);
01869 
01870   if (aFontID) *aFontID = 0;
01871 
01872   aNumCharsFit = data.mNumCharsFit;
01873   aDimensions.width = data.mWidth;
01874 
01876   // Post-processing for the ascent and descent:
01877   //
01878   // The width of the last word is included in the final width, but its
01879   // ascent and descent are kept aside for the moment. The problem is that
01880   // line-breaking may occur _before_ the last word, and we don't want its
01881   // ascent and descent to interfere. We can re-measure the last word and
01882   // substract its width later. However, we need a special care for the ascent
01883   // and descent at the break-point. The idea is to keep the ascent and descent
01884   // of the last word separate, and let layout consider them later when it has
01885   // determined that line-breaking doesn't occur before the last word.
01886   //
01887   // Therefore, there are two things to do:
01888   // 1. Determine the ascent and descent up to where line-breaking may occur.
01889   // 2. Determine the ascent and descent of the remainder.
01890   //    For efficiency however, it is okay to bail out early if there is only
01891   //    one font (in this case, the height of the last word has no special
01892   //    effect on the total height).
01893 
01894   // aLastWordDimensions.width should be set to -1 to reply that we don't
01895   // know the width of the last word since we measure multiple words
01896   aLastWordDimensions.Clear();
01897   aLastWordDimensions.width = -1;
01898 
01899   PRInt32 count = fonts.Count();
01900   if (!count)
01901     return NS_OK;
01902   nsFontXlib *fontXlib = (nsFontXlib *)fonts[0];
01903   NS_ASSERTION(fontXlib, "internal error in do_BreakGetTextDimensions");
01904   aDimensions.ascent = fontXlib->mMaxAscent;
01905   aDimensions.descent = fontXlib->mMaxDescent;
01906 
01907   // fast path - normal case, quick return if there is only one font
01908   if (count == 1)
01909     return NS_OK;
01910 
01911   // get the last break index.
01912   // If there is only one word, we end up with lastBreakIndex = 0. We don't
01913   // need to worry about aLastWordDimensions in this case too. But if we didn't
01914   // return earlier, it would mean that the unique word needs several fonts
01915   // and we will still have to loop over the fonts to return the final height
01916   PRInt32 lastBreakIndex = 0;
01917   while (aBreaks[lastBreakIndex] < aNumCharsFit)
01918     ++lastBreakIndex;
01919 
01920   const PRUnichar* lastWord = (lastBreakIndex > 0) 
01921     ? aString + aBreaks[lastBreakIndex-1]
01922     : aString + aNumCharsFit; // let it point outside to play nice with the loop
01923 
01924   // now get the desired ascent and descent information... this is however
01925   // a very fast loop of the order of the number of additional fonts
01926 
01927   PRInt32 currFont = 0;
01928   const PRUnichar* pstr = aString;
01929   const PRUnichar* last = aString + aNumCharsFit;
01930 
01931   while (pstr < last) {
01932     fontXlib = (nsFontXlib*)fonts[currFont];
01933     PRUnichar* nextOffset = (PRUnichar*)offsets[++currFont]; 
01934 
01935     // For consistent word-wrapping, we are going to handle the whitespace
01936     // character with special care because a whitespace character can come
01937     // from a font different from that of the previous word. If 'x', 'y', 'z',
01938     // are Unicode points that require different fonts, we want 'xyz <br>'
01939     // and 'xyz<br>' to have the same height because it gives a more stable
01940     // rendering, especially when the window is resized at the edge of the word.
01941     // If we don't do this, a 'tall' trailing whitespace, i.e., if the whitespace
01942     // happens to come from a font with a bigger ascent and/or descent than all
01943     // current fonts on the line, this can cause the next lines to be shifted
01944     // down when the window is slowly resized to fit that whitespace.
01945     if (*pstr == ' ') {
01946       // skip pass the whitespace to ignore the height that it may contribute
01947       ++pstr;
01948       // get out if we reached the end
01949       if (pstr == last) {
01950         break;
01951       }
01952       // switch to the next font if we just passed the current font 
01953       if (pstr == nextOffset) {
01954         fontXlib = (nsFontXlib*)fonts[currFont];
01955         nextOffset = (PRUnichar*)offsets[++currFont];
01956       } 
01957     }
01958 
01959     // see if the last word intersects with the current font
01960     // (we are testing for 'nextOffset-1 >= lastWord' since the
01961     // current font ends at nextOffset-1)
01962     if (nextOffset > lastWord) {
01963       if (aLastWordDimensions.ascent < fontXlib->mMaxAscent) {
01964         aLastWordDimensions.ascent = fontXlib->mMaxAscent;
01965       }
01966       if (aLastWordDimensions.descent < fontXlib->mMaxDescent) {
01967         aLastWordDimensions.descent = fontXlib->mMaxDescent;
01968       }
01969     }
01970 
01971     // see if we have not reached the last word yet
01972     if (pstr < lastWord) {
01973       if (aDimensions.ascent < fontXlib->mMaxAscent) {
01974         aDimensions.ascent = fontXlib->mMaxAscent;
01975       }
01976       if (aDimensions.descent < fontXlib->mMaxDescent) {
01977         aDimensions.descent = fontXlib->mMaxDescent;
01978       }
01979     }
01980 
01981     // advance to where the next font starts
01982     pstr = nextOffset;
01983   }
01984 
01985   return NS_OK;
01986 }
01987 
01988 NS_IMETHODIMP
01989 nsRenderingContextXlib::GetTextDimensions(const char* aString, PRUint32 aLength,
01990                                           nsTextDimensions& aDimensions)
01991 {
01992   mFontMetrics->GetMaxAscent(aDimensions.ascent);
01993   mFontMetrics->GetMaxDescent(aDimensions.descent);
01994   return GetWidth(aString, aLength, aDimensions.width);
01995 }
01996 
01997 NS_IMETHODIMP
01998 nsRenderingContextXlib::GetTextDimensions(const PRUnichar* aString, PRUint32 aLength,
01999                                           nsTextDimensions& aDimensions, PRInt32* aFontID)
02000 {
02001   aDimensions.Clear();
02002   if (0 < aLength) {
02003     NS_ENSURE_TRUE(aString != nsnull, NS_ERROR_FAILURE);
02004 
02005     nsFontMetricsXlib *metrics = NS_REINTERPRET_CAST(nsFontMetricsXlib *, mFontMetrics.get());
02006 
02007     NS_ENSURE_TRUE(metrics != nsnull, NS_ERROR_FAILURE);
02008 
02009     nsFontXlib* prevFont = nsnull;
02010     int rawWidth = 0, rawAscent = 0, rawDescent = 0;
02011     PRUint32 start = 0;
02012     PRUint32 i;
02013     for (i = 0; i < aLength; i++) {
02014       PRUnichar c = aString[i];
02015       nsFontXlib  *currFont = nsnull;
02016       nsFontXlib **font = metrics->mLoadedFonts;
02017       nsFontXlib **end = &metrics->mLoadedFonts[metrics->mLoadedFontsCount];
02018       while (font < end) {
02019         if (CCMAP_HAS_CHAR((*font)->mCCMap, c)) {
02020           currFont = *font;
02021           goto FoundFont; // for speed -- avoid "if" statement
02022         }
02023         font++;
02024       }
02025       currFont = metrics->FindFont(c);
02026 FoundFont:
02027       // XXX avoid this test by duplicating code -- erik
02028       if (prevFont) {
02029         if (currFont != prevFont) {
02030           rawWidth += prevFont->GetWidth(&aString[start], i - start);
02031           if (rawAscent < prevFont->mMaxAscent)
02032             rawAscent = prevFont->mMaxAscent;
02033           if (rawDescent < prevFont->mMaxDescent)
02034             rawDescent = prevFont->mMaxDescent;
02035           prevFont = currFont;
02036           start = i;
02037         }
02038       }
02039       else {
02040         prevFont = currFont;
02041         start = i;
02042       }
02043     }
02044 
02045     if (prevFont) {
02046       rawWidth += prevFont->GetWidth(&aString[start], i - start);
02047       if (rawAscent < prevFont->mMaxAscent)
02048         rawAscent = prevFont->mMaxAscent;
02049       if (rawDescent < prevFont->mMaxDescent)
02050         rawDescent = prevFont->mMaxDescent;
02051     }
02052 
02053     aDimensions.width = NSToCoordRound(rawWidth * mP2T);
02054     aDimensions.ascent = NSToCoordRound(rawAscent * mP2T);
02055     aDimensions.descent = NSToCoordRound(rawDescent * mP2T);
02056   }
02057   if (nsnull != aFontID)
02058     *aFontID = 0;
02059 
02060   return NS_OK;
02061 }
02062 
02063 NS_IMETHODIMP
02064 nsRenderingContextXlib::DrawString(const char *aString, PRUint32 aLength,
02065                                    nscoord aX, nscoord aY,
02066                                    const nscoord* aSpacing)
02067 {
02068   nsresult res = NS_OK;
02069 
02070   if (aLength) {
02071     NS_ENSURE_TRUE(mTranMatrix  != nsnull, NS_ERROR_FAILURE);
02072     NS_ENSURE_TRUE(mSurface     != nsnull, NS_ERROR_FAILURE);
02073     NS_ENSURE_TRUE(aString      != nsnull, NS_ERROR_FAILURE);
02074     NS_ENSURE_TRUE(mCurrentFont != nsnull, NS_ERROR_FAILURE);
02075 
02076     nscoord x = aX;
02077     nscoord y = aY;
02078 
02079     UpdateGC();
02080 
02081     nsXFont *xFont = mCurrentFont->GetXFont();
02082     if (nsnull != aSpacing) {
02083       // Render the string, one character at a time...
02084       const char* end = aString + aLength;
02085       while (aString < end) {
02086         char ch = *aString++;
02087         nscoord xx = x;
02088         nscoord yy = y;
02089         mTranMatrix->TransformCoord(&xx, &yy);
02090 #ifdef USE_FREETYPE
02091         if (mCurrentFont->IsFreeTypeFont()) {
02092           // this function is only supposed to be called for ascii data
02093           res = mCurrentFont->DrawString(this, mSurface, xx, yy, 
02094                             NS_ConvertASCIItoUTF16(aString, aLength).get(),
02095                             aLength);
02096         }
02097         else
02098 #endif /* USE_FREETYPE */
02099         if (!mCurrentFont->GetXFontIs10646()) {
02100           // 8 bit data with an 8 bit font
02101           NS_ASSERTION(xFont->IsSingleByte(),"wrong string/font size");
02102           xFont->DrawText8(mSurface->GetDrawable(), *mGC, xx, yy, &ch, 1);
02103         }
02104         else {
02105           // we have 8 bit data but a 16 bit font
02106           NS_ASSERTION(!xFont->IsSingleByte(),"wrong string/font size");
02107           Widen8To16AndDraw(mSurface->GetDrawable(), xFont, *mGC,
02108                                                 xx, yy, &ch, 1);
02109         }
02110         x += *aSpacing++;
02111       }
02112     }
02113     else {
02114       mTranMatrix->TransformCoord(&x, &y);
02115 #ifdef USE_FREETYPE
02116       if (mCurrentFont->IsFreeTypeFont()) {
02117         // this function is only supposed to be called for ascii data
02118         res = mCurrentFont->DrawString(this, mSurface, x, y, 
02119                           NS_ConvertASCIItoUTF16(aString, aLength).get(),
02120                           aLength);
02121       }
02122       else
02123 #endif /* USE_FREETYPE */
02124       if (!mCurrentFont->GetXFontIs10646()) { // keep 8 bit path fast
02125         // 8 bit data with an 8 bit font
02126         NS_ASSERTION(xFont->IsSingleByte(),"wrong string/font size");
02127         xFont->DrawText8(mSurface->GetDrawable(), *mGC, x, y, aString, aLength);
02128       }
02129       else {
02130         // we have 8 bit data but a 16 bit font
02131         NS_ASSERTION(!xFont->IsSingleByte(),"wrong string/font size");
02132         Widen8To16AndDraw(mSurface->GetDrawable(), xFont, *mGC,
02133                                              x, y, aString, aLength);
02134       }
02135     }
02136   }
02137 
02138 #ifdef DISABLED_FOR_NOW
02139   //this is no longer to be done by this API, but another
02140   //will take it's place that will need this code again. MMP
02141   if (mFontMetrics)
02142   {
02143     PRUint8 deco = mFontMetrics->Font().decorations;
02144 
02145     if (deco & NS_FONT_DECORATION_OVERLINE)
02146       DrawLine(aX, aY, aX + aWidth, aY);
02147 
02148     if (deco & NS_FONT_DECORATION_UNDERLINE)
02149     {
02150       nscoord ascent,descent;
02151 
02152       mFontMetrics->GetMaxAscent(ascent);
02153       mFontMetrics->GetMaxDescent(descent);
02154 
02155       DrawLine(aX, aY + ascent + (descent >> 1),
02156                aX + aWidth, aY + ascent + (descent >> 1));
02157     }
02158 
02159     if (deco & NS_FONT_DECORATION_LINE_THROUGH)
02160     {
02161       nscoord height;
02162 
02163       mFontMetrics->GetHeight(height);
02164 
02165       DrawLine(aX, aY + (height >> 1), aX + aWidth, aY + (height >> 1));
02166     }
02167   }
02168 #endif /* DISABLED_FOR_NOW */
02169 
02170   return res;
02171 }
02172 
02173 NS_IMETHODIMP
02174 nsRenderingContextXlib::DrawString(const PRUnichar* aString, PRUint32 aLength,
02175                                    nscoord aX, nscoord aY,
02176                                    PRInt32 aFontID,
02177                                    const nscoord* aSpacing)
02178 {
02179   if (aLength && mFontMetrics) {
02180     NS_ENSURE_TRUE(mTranMatrix != nsnull, NS_ERROR_FAILURE);
02181     NS_ENSURE_TRUE(mSurface    != nsnull, NS_ERROR_FAILURE);
02182     NS_ENSURE_TRUE(aString     != nsnull, NS_ERROR_FAILURE);
02183 
02184     nscoord x = aX;
02185     nscoord y = aY;
02186 
02187     mTranMatrix->TransformCoord(&x, &y);
02188 
02189     nsFontMetricsXlib *metrics = NS_REINTERPRET_CAST(nsFontMetricsXlib *, mFontMetrics.get());
02190     nsFontXlib *prevFont = nsnull;
02191     PRUint32 start = 0;
02192     PRUint32 i;
02193     for (i = 0; i < aLength; i++) {
02194       PRUnichar c = aString[i];
02195       nsFontXlib* currFont = nsnull;
02196       nsFontXlib** font = metrics->mLoadedFonts;
02197       nsFontXlib** lastFont = &metrics->mLoadedFonts[metrics->mLoadedFontsCount];
02198       while (font < lastFont) {
02199         if (CCMAP_HAS_CHAR((*font)->mCCMap, c)) {
02200           currFont = *font;
02201           goto FoundFont; // for speed -- avoid "if" statement
02202         }
02203         font++;
02204       }
02205       currFont = metrics->FindFont(c);
02206 FoundFont:
02207       // XXX avoid this test by duplicating code -- erik
02208       if (prevFont) {
02209         if (currFont != prevFont) {
02210           if (aSpacing) {
02211             const PRUnichar* str = &aString[start];
02212             const PRUnichar* end = &aString[i];
02213 
02214             // save off mCurrentFont and set it so that we cache the GC's font correctly
02215             nsFontXlib *oldFont = mCurrentFont;
02216             mCurrentFont = prevFont;
02217             UpdateGC();
02218 
02219             while (str < end) {
02220               x = aX;
02221               y = aY;
02222               mTranMatrix->TransformCoord(&x, &y);
02223               prevFont->DrawString(this, mSurface, x, y, str, 1);
02224               aX += *aSpacing++;
02225               str++;
02226             }
02227             mCurrentFont = oldFont;
02228           }
02229           else {
02230             nsFontXlib *oldFont = mCurrentFont;
02231             mCurrentFont = prevFont;
02232             UpdateGC();
02233             x += prevFont->DrawString(this, mSurface, x, y, &aString[start],
02234                                       i - start);
02235             mCurrentFont = oldFont;
02236           }
02237           prevFont = currFont;
02238           start = i;
02239         }
02240       }
02241       else {
02242         prevFont = currFont;
02243         start = i;
02244       }
02245     }
02246 
02247     if (prevFont) {
02248       nsFontXlib *oldFont = mCurrentFont;
02249       mCurrentFont = prevFont;
02250       UpdateGC();
02251     
02252       if (aSpacing) {
02253         const PRUnichar* str = &aString[start];
02254         const PRUnichar* end = &aString[i];
02255         while (str < end) {
02256           x = aX;
02257           y = aY;
02258           mTranMatrix->TransformCoord(&x, &y);
02259           prevFont->DrawString(this, mSurface, x, y, str, 1);
02260           aX += *aSpacing++;
02261           str++;
02262         }
02263       }
02264       else {
02265         prevFont->DrawString(this, mSurface, x, y, &aString[start], i - start);
02266       }
02267 
02268       mCurrentFont = oldFont;
02269     }
02270   }
02271 
02272   return NS_OK;
02273 }
02274 
02275 NS_IMETHODIMP
02276 nsRenderingContextXlib::DrawString(const nsString& aString,
02277                                    nscoord aX, nscoord aY,
02278                                    PRInt32 aFontID,
02279                                    const nscoord* aSpacing)
02280 {
02281   return DrawString(aString.get(), aString.Length(),
02282                     aX, aY, aFontID, aSpacing);
02283 }
02284 
02285 NS_IMETHODIMP
02286 nsRenderingContextXlib::CopyOffScreenBits(nsIDrawingSurface* aSrcSurf, PRInt32 aSrcX, PRInt32 aSrcY,
02287                                           const nsRect &aDestBounds, PRUint32 aCopyFlags)
02288 {
02289   PR_LOG(RenderingContextXlibLM, PR_LOG_DEBUG, ("nsRenderingContextXlib::CopyOffScreenBits()\n"));
02290 
02291   PRInt32                 srcX = aSrcX;
02292   PRInt32                 srcY = aSrcY;
02293   nsRect                  drect = aDestBounds;
02294   nsIDrawingSurfaceXlib  *destsurf;
02295 
02296   NS_ENSURE_TRUE(mTranMatrix != nsnull, NS_ERROR_FAILURE);
02297   NS_ENSURE_TRUE(mSurface    != nsnull, NS_ERROR_FAILURE);
02298   NS_ENSURE_TRUE(aSrcSurf    != nsnull, NS_ERROR_FAILURE);
02299     
02300   if (aCopyFlags & NS_COPYBITS_TO_BACK_BUFFER) {
02301     destsurf = mSurface;
02302   }
02303   else
02304   {
02305     NS_ENSURE_TRUE(mOffscreenSurface != nsnull, NS_ERROR_FAILURE);
02306     destsurf = mOffscreenSurface;
02307   }
02308   
02309   if (aCopyFlags & NS_COPYBITS_XFORM_SOURCE_VALUES)
02310     mTranMatrix->TransformCoord(&srcX, &srcY);
02311   
02312   if (aCopyFlags & NS_COPYBITS_XFORM_DEST_VALUES)
02313     mTranMatrix->TransformCoord(&drect.x, &drect.y, &drect.width, &drect.height);
02314   
02315   //XXX flags are unused. that would seem to mean that there is
02316   //inefficiency somewhere... MMP
02317 
02318   UpdateGC();
02319   Drawable destdrawable; destsurf->GetDrawable(destdrawable);
02320   Drawable srcdrawable; ((nsIDrawingSurfaceXlib *)aSrcSurf)->GetDrawable(srcdrawable);
02321 
02322   ::XCopyArea(mDisplay,
02323               srcdrawable,
02324               destdrawable,
02325               *mGC,
02326               srcX, srcY,
02327               drect.width, drect.height,
02328               drect.x, drect.y);
02329 
02330   return NS_OK;
02331 }
02332 
02333 NS_IMETHODIMP
02334 nsRenderingContextXlib::RetrieveCurrentNativeGraphicData(void ** ngd)
02335 {
02336   PR_LOG(RenderingContextXlibLM, PR_LOG_DEBUG, ("nsRenderingContextXlib::RetrieveCurrentNativeGraphicData()\n"));
02337   *ngd = nsnull;
02338   return NS_OK;
02339 }
02340 
02341 #ifdef MOZ_MATHML
02342 static
02343 void Widen8To16AndGetTextExtents(nsXFont    *xFont,  
02344                                  const char *text,
02345                                  int         text_length,
02346                                  int        *lbearing,
02347                                  int        *rbearing,
02348                                  int        *width,
02349                                  int        *ascent,
02350                                  int        *descent)
02351 {
02352   NS_ASSERTION(!xFont->IsSingleByte(),"wrong string/font size");
02353   XChar2b buf[WIDEN_8_TO_16_BUF_SIZE];
02354   XChar2b *p = buf;
02355   int uchar_size;
02356 
02357   if (text_length > WIDEN_8_TO_16_BUF_SIZE) {
02358     p = (XChar2b*)malloc(text_length*sizeof(XChar2b));
02359     if (!p) { // handle malloc failure
02360       *lbearing = 0;
02361       *rbearing = 0;
02362       *width    = 0;
02363       *ascent   = 0;
02364       *descent  = 0;
02365       return;
02366     }
02367   }
02368 
02369   uchar_size = Widen8To16AndMove(text, text_length, p);
02370   xFont->TextExtents16(p, uchar_size/2,
02371                        lbearing, 
02372                        rbearing, 
02373                        width, 
02374                        ascent, 
02375                        descent);
02376 
02377   if (text_length > WIDEN_8_TO_16_BUF_SIZE) {
02378     free((char*)p);
02379   }
02380 }
02381 
02382 NS_IMETHODIMP
02383 nsRenderingContextXlib::GetBoundingMetrics(const char*        aString, 
02384                                            PRUint32           aLength,
02385                                            nsBoundingMetrics& aBoundingMetrics)
02386 {
02387   nsresult res = NS_OK;
02388   aBoundingMetrics.Clear();
02389   if (aString && 0 < aLength) {
02390     NS_ENSURE_TRUE(mCurrentFont != nsnull, NS_ERROR_FAILURE);
02391     nsXFont *xFont = mCurrentFont->GetXFont();
02392 #ifdef USE_FREETYPE
02393     if (mCurrentFont->IsFreeTypeFont()) {
02394       // this function is only supposed to be called for ascii data
02395       res = mCurrentFont->GetBoundingMetrics(
02396                         NS_ConvertASCIItoUTF16(aString, aLength).get(),
02397                         aLength, aBoundingMetrics);
02398     }
02399     else
02400 #endif /* USE_FREETYPE */
02401     if (!mCurrentFont->GetXFontIs10646()) {
02402         // 8 bit data with an 8 bit font
02403         NS_ASSERTION(xFont->IsSingleByte(), "GetBoundingMetrics: wrong string/font size");
02404         xFont->TextExtents8(aString, aLength,
02405                             &aBoundingMetrics.leftBearing, 
02406                             &aBoundingMetrics.rightBearing, 
02407                             &aBoundingMetrics.width, 
02408                             &aBoundingMetrics.ascent, 
02409                             &aBoundingMetrics.descent);
02410     }
02411     else {
02412         // we have 8 bit data but a 16 bit font
02413         NS_ASSERTION(!xFont->IsSingleByte(), "GetBoundingMetrics: wrong string/font size");
02414         Widen8To16AndGetTextExtents(mCurrentFont->GetXFont(), aString, aLength,
02415                                     &aBoundingMetrics.leftBearing, 
02416                                     &aBoundingMetrics.rightBearing, 
02417                                     &aBoundingMetrics.width, 
02418                                     &aBoundingMetrics.ascent, 
02419                                     &aBoundingMetrics.descent);
02420     }
02421 
02422     aBoundingMetrics.leftBearing = NSToCoordRound(aBoundingMetrics.leftBearing * mP2T);
02423     aBoundingMetrics.rightBearing = NSToCoordRound(aBoundingMetrics.rightBearing * mP2T);
02424     aBoundingMetrics.width = NSToCoordRound(aBoundingMetrics.width * mP2T);
02425     aBoundingMetrics.ascent = NSToCoordRound(aBoundingMetrics.ascent * mP2T);
02426     aBoundingMetrics.descent = NSToCoordRound(aBoundingMetrics.descent * mP2T);
02427   }
02428 
02429   return res;
02430 }
02431 
02432 NS_IMETHODIMP
02433 nsRenderingContextXlib::GetBoundingMetrics(const PRUnichar*   aString, 
02434                                            PRUint32           aLength,
02435                                            nsBoundingMetrics& aBoundingMetrics,
02436                                            PRInt32*           aFontID)
02437 {
02438   aBoundingMetrics.Clear(); 
02439   if (0 < aLength) {
02440     NS_ENSURE_TRUE(aString != nsnull, NS_ERROR_FAILURE);
02441 
02442     nsFontMetricsXlib *metrics  = NS_REINTERPRET_CAST(nsFontMetricsXlib *, mFontMetrics.get());
02443     nsFontXlib        *prevFont = nsnull;
02444 
02445     nsBoundingMetrics rawbm;
02446     PRBool firstTime = PR_TRUE;
02447     PRUint32 start = 0;
02448     PRUint32 i;
02449     for (i = 0; i < aLength; i++) {
02450       PRUnichar c = aString[i];
02451       nsFontXlib  *currFont = nsnull;
02452       nsFontXlib **font = metrics->mLoadedFonts;
02453       nsFontXlib **end = &metrics->mLoadedFonts[metrics->mLoadedFontsCount];
02454       while (font < end) {
02455         if (CCMAP_HAS_CHAR((*font)->mCCMap, c)) {
02456           currFont = *font;
02457           goto FoundFont; // for speed -- avoid "if" statement
02458         }
02459         font++;
02460       }
02461       currFont = metrics->FindFont(c);
02462   FoundFont:
02463       // XXX avoid this test by duplicating code -- erik
02464       if (prevFont) {
02465         if (currFont != prevFont) {
02466           prevFont->GetBoundingMetrics((const PRUnichar*) &aString[start],
02467                                        i - start, rawbm);
02468           if (firstTime) {
02469             firstTime = PR_FALSE;
02470             aBoundingMetrics = rawbm;
02471           } 
02472           else {
02473             aBoundingMetrics += rawbm;
02474           }
02475           prevFont = currFont;
02476           start = i;
02477         }
02478       }
02479       else {
02480         prevFont = currFont;
02481         start = i;
02482       }
02483     }
02484     
02485     if (prevFont) {
02486       prevFont->GetBoundingMetrics((const PRUnichar*) &aString[start],
02487                                    i - start, rawbm);
02488       if (firstTime) {
02489         aBoundingMetrics = rawbm;
02490       }
02491       else {
02492         aBoundingMetrics += rawbm;
02493       }
02494     }
02495     // convert to app units
02496     aBoundingMetrics.leftBearing = NSToCoordRound(aBoundingMetrics.leftBearing * mP2T);
02497     aBoundingMetrics.rightBearing = NSToCoordRound(aBoundingMetrics.rightBearing * mP2T);
02498     aBoundingMetrics.width = NSToCoordRound(aBoundingMetrics.width * mP2T);
02499     aBoundingMetrics.ascent = NSToCoordRound(aBoundingMetrics.ascent * mP2T);
02500     aBoundingMetrics.descent = NSToCoordRound(aBoundingMetrics.descent * mP2T);
02501   }
02502   if (nsnull != aFontID)
02503     *aFontID = 0;
02504 
02505   return NS_OK;
02506 }
02507 #endif /* MOZ_MATHML */
02508 
02509 NS_IMETHODIMP
02510 nsRenderingContextXlib::DrawImage(imgIContainer *aImage, const nsRect & aSrcRect, const nsRect & aDestRect)
02511 {
02512   PR_LOG(RenderingContextXlibLM, PR_LOG_DEBUG, ("nsRenderingContextXlib::DrawImage()\n"));
02513   UpdateGC();
02514   return nsRenderingContextImpl::DrawImage(aImage, aSrcRect, aDestRect);
02515 }
02516 
02517 NS_IMETHODIMP
02518 nsRenderingContextXlib::GetBackbuffer(const nsRect &aRequestedSize,
02519                                       const nsRect &aMaxSize,
02520                                       PRBool aForBlending,
02521                                       nsIDrawingSurface* &aBackbuffer)
02522 {
02523   PR_LOG(RenderingContextXlibLM, PR_LOG_DEBUG, ("nsRenderingContextXlib::GetBackbuffer()\n"));
02524   /* Do not cache the backbuffer. On X11 it is more efficient to allocate
02525    * the backbuffer as needed and it doesn't cause a performance hit. @see bug 95952 */
02526   return AllocateBackbuffer(aRequestedSize, aMaxSize, aBackbuffer, PR_FALSE, 0);
02527 }
02528  
02529 NS_IMETHODIMP
02530 nsRenderingContextXlib::ReleaseBackbuffer(void) 
02531 {
02532   PR_LOG(RenderingContextXlibLM, PR_LOG_DEBUG, ("nsRenderingContextXlib::ReleaseBackbuffer()\n"));
02533   /* Do not cache the backbuffer. On X11 it is more efficient to allocate
02534    * the backbuffer as needed and it doesn't cause a performance hit. @see bug 95952 */
02535   return DestroyCachedBackbuffer();
02536 }
02537