Back to index

lightning-sunbird  0.9+nobinonly
nsRenderingContextMac.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  *   Pierre Phaneuf <pp@ludusdesign.com>
00024  *   Mark Mentovai <mark@moxienet.com>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either of the GNU General Public License Version 2 or later (the "GPL"),
00028  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 #include "nsIInterfaceRequestorUtils.h" 
00041 #include "nsIServiceManager.h"
00042 #include "nsRenderingContextMac.h"
00043 #include "nsDeviceContextMac.h"
00044 #include "nsFontMetricsMac.h"
00045 #include "nsIRegion.h"
00046 #include "nsIEnumerator.h"
00047 #include "nsRegionMac.h"
00048 #include "nsGraphicState.h"
00049 
00050 #include "nsTransform2D.h"
00051 #include "nsVoidArray.h"
00052 #include "nsGfxCIID.h"
00053 #include "nsGfxUtils.h"
00054 #include "nsCOMPtr.h"
00055 
00056 #ifdef MOZ_WIDGET_COCOA
00057 #include "nsIQDFlushManager.h"
00058 #endif
00059 
00060 #include "plhash.h"
00061 
00062 #include <FixMath.h>
00063 #include <Gestalt.h>
00064 #include <Quickdraw.h>
00065 
00066 #include "nsRegionPool.h"
00067 #include "nsFontUtils.h"
00068 
00069 #include "nsCarbonHelpers.h"
00070 
00071 #define STACK_THRESHOLD 1000
00072 
00073 
00074 //------------------------------------------------------------------------
00075 
00076 nsRenderingContextMac::nsRenderingContextMac()
00077 : mP2T(1.0f)
00078 , mContext(nsnull)
00079 , mCurrentSurface(nsnull)
00080 , mPort(nsnull)
00081 , mGS(nsnull)
00082 , mChanges(kEverythingChanged)
00083 , mRightToLeftText(PR_FALSE)
00084 {
00085        mFrontSurface                      = new nsDrawingSurfaceMac();
00086        NS_IF_ADDREF(mFrontSurface);
00087 }
00088 
00089 
00090 //------------------------------------------------------------------------
00091 
00092 nsRenderingContextMac::~nsRenderingContextMac()
00093 {
00094        // restore stuff
00095        NS_IF_RELEASE(mContext);
00096 
00097        // release surfaces
00098        NS_IF_RELEASE(mFrontSurface);
00099        NS_IF_RELEASE(mCurrentSurface);
00100 
00101        mPort = nsnull;
00102        mGS = nsnull;
00103 
00104        // delete the stack and its contents
00105   PRInt32 cnt = mGSStack.Count();
00106          for (PRInt32 i = 0; i < cnt; i ++) {
00107     nsGraphicState* gs = (nsGraphicState*)mGSStack.ElementAt(i);
00108        if (gs != nsnull)
00109               sGraphicStatePool.ReleaseGS(gs); //delete gs;
00110          }
00111 
00112        NS_ASSERTION(ValidateDrawingState(), "Bad drawing state");
00113 }
00114 
00115 
00116 NS_IMPL_ISUPPORTS1(nsRenderingContextMac, nsIRenderingContext)
00117 
00118 
00119 //------------------------------------------------------------------------
00120 
00121 NS_IMETHODIMP nsRenderingContextMac::Init(nsIDeviceContext* aContext, nsIWidget* aWindow)
00122 {
00123        NS_ASSERTION(ValidateDrawingState(), "Bad drawing state");
00124 
00125        // make sure all allocations in the constructor succeeded.
00126        if (nsnull == mFrontSurface)
00127               return NS_ERROR_OUT_OF_MEMORY;
00128               
00129        if (nsnull == aWindow->GetNativeData(NS_NATIVE_WINDOW))
00130               return NS_ERROR_NOT_INITIALIZED;
00131 
00132        if (aContext != mContext) {
00133               NS_IF_RELEASE(mContext);
00134               mContext = aContext;
00135               NS_IF_ADDREF(mContext);
00136        }
00137 
00138        // select the surface
00139        mFrontSurface->Init(aWindow);
00140        SelectDrawingSurface(mFrontSurface);
00141 
00142        // NOTE: here, we used to clip out the children from mGS->mMainRegion
00143        // and copy the resulting region into mMainRegion and mClipRegion.
00144        // This is no longer necessary because when initializing mGS from an nsIWidget, we
00145        // call GetNativeData(NS_NATIVE_REGION) that now returns the widget's visRegion
00146        // with the children already clipped out (as well as the areas masked by the 
00147        // widget's parents).
00148 
00149        return NS_OK;
00150 }
00151 
00152 //------------------------------------------------------------------------
00153 
00154 // should only be called for an offscreen drawing surface, without an offset or clip region
00155 NS_IMETHODIMP nsRenderingContextMac::Init(nsIDeviceContext* aContext, nsIDrawingSurface* aSurface)
00156 {
00157        // make sure all allocations in the constructor succeeded.
00158        if (nsnull == mFrontSurface)
00159               return NS_ERROR_OUT_OF_MEMORY;
00160               
00161        mContext = aContext;
00162        NS_IF_ADDREF(mContext);
00163 
00164        // select the surface
00165        nsDrawingSurfaceMac* surface = static_cast<nsDrawingSurfaceMac*>(aSurface);
00166        SelectDrawingSurface(surface);
00167 
00168        return NS_OK;
00169 }
00170 
00171 //------------------------------------------------------------------------
00172 
00173 // used by nsDeviceContextMac::CreateRenderingContext() for printing
00174 nsresult nsRenderingContextMac::Init(nsIDeviceContext* aContext, CGrafPtr aPort)
00175 {
00176        // make sure all allocations in the constructor succeeded.
00177        if (nsnull == mFrontSurface)
00178               return NS_ERROR_OUT_OF_MEMORY;
00179               
00180        mContext = aContext;
00181        NS_IF_ADDREF(mContext);
00182 
00183        // select the surface
00184        mFrontSurface->Init(aPort);
00185        SelectDrawingSurface(mFrontSurface);
00186 
00187        return NS_OK;
00188 }
00189 
00190 //------------------------------------------------------------------------
00191 
00192 void nsRenderingContextMac::SelectDrawingSurface(nsDrawingSurfaceMac* aSurface, PRUint32 aChanges)
00193 {
00194   NS_PRECONDITION(aSurface != nsnull, "null surface");
00195        if (! aSurface)
00196               return;
00197 
00198   NS_ASSERTION(ValidateDrawingState(), "Bad drawing state");
00199 
00200        // if surface is changing, be extra conservative about graphic state changes.
00201        if (mCurrentSurface != aSurface)
00202        {
00203               aChanges = kEverythingChanged;
00204 
00205               NS_IF_RELEASE(mCurrentSurface);
00206               mCurrentSurface = aSurface;
00207               NS_IF_ADDREF(mCurrentSurface);
00208        }
00209        
00210        CGrafPtr    newPort;
00211        aSurface->GetGrafPtr(&newPort);
00212        mPort = newPort;
00213        mGS = aSurface->GetGS();
00214        mTranMatrix = &(mGS->mTMatrix);
00215 
00216   nsGraphicsUtils::SafeSetPort(mPort);
00217 
00218 #ifndef MOZ_WIDGET_COCOA
00219   // Cocoa widgets automatically set the correct origin, and 
00220   // it can differ from this value (because of an oddity where
00221   // the widget shrinks when its partially offscreen).  
00222        ::SetOrigin(-mGS->mOffx, -mGS->mOffy);           // line order...
00223 #endif
00224 
00225        if (aChanges & kClippingChanged)
00226               ::SetClip(mGS->mClipRegion);                     // ...does matter
00227 
00228        ::PenNormal();
00229        ::PenMode(patCopy);
00230        ::TextMode(srcOr);
00231 
00232        if (aChanges & kColorChanged)
00233               SetColor(mGS->mColor);
00234 
00235        if (mGS->mFontMetrics && (aChanges & kFontChanged))
00236               SetFont(mGS->mFontMetrics);
00237        
00238        if (!mContext) return;
00239        
00240        // GS and context initializations
00241 #if 0
00242        ((nsDeviceContextMac *)mContext)->InstallColormap();
00243 #endif
00244 
00245        mP2T = mContext->DevUnitsToAppUnits();
00246 
00247        if (mGS->mTMatrix.GetType() == MG_2DIDENTITY) {
00248               // apply the new scaling
00249               float app2dev;
00250               app2dev = mContext->AppUnitsToDevUnits();
00251               mGS->mTMatrix.AddScale(app2dev, app2dev);
00252        }
00253 
00254   NS_ASSERTION(ValidateDrawingState(), "Bad drawing state");
00255 }
00256 
00257 
00258 //------------------------------------------------------------------------
00259 
00260 nsresult nsRenderingContextMac::SetPortTextState()
00261 {
00262        NS_PRECONDITION(mGS->mFontMetrics != nsnull, "No font metrics in SetPortTextState");
00263        
00264        if (nsnull == mGS->mFontMetrics)
00265               return NS_ERROR_NULL_POINTER;
00266 
00267        NS_PRECONDITION(mContext != nsnull, "No device context in SetPortTextState");
00268        
00269        if (nsnull == mContext)
00270               return NS_ERROR_NULL_POINTER;
00271 
00272        TextStyle            theStyle;
00273        nsFontUtils::GetNativeTextStyle(*mGS->mFontMetrics, *mContext, theStyle);
00274 
00275        ::TextFont(theStyle.tsFont);
00276        ::TextSize(theStyle.tsSize);
00277        ::TextFace(theStyle.tsFace);
00278 
00279        return NS_OK;
00280 }
00281 
00282 
00283 //------------------------------------------------------------------------
00284 
00285 void nsRenderingContextMac::SetupPortState()
00286 {
00287   nsGraphicsUtils::SafeSetPort(mPort);
00288 #ifndef MOZ_WIDGET_COCOA
00289        ::SetOrigin(-mGS->mOffx, -mGS->mOffy);
00290 #endif
00291        ::SetClip(mGS->mClipRegion);
00292 }
00293 
00294 #pragma mark -
00295 
00296 //------------------------------------------------------------------------
00297 
00298 NS_IMETHODIMP nsRenderingContextMac::PushState(void)
00299 {
00300        // create a GS
00301        nsGraphicState * gs = sGraphicStatePool.GetNewGS();
00302        if (!gs)
00303               return NS_ERROR_OUT_OF_MEMORY;
00304 
00305        // save the current set of graphics changes.
00306        mGS->SetChanges(mChanges);
00307 
00308        // copy the current GS into it
00309        gs->Duplicate(mGS);
00310 
00311        // put the new GS at the end of the stack
00312        mGSStack.AppendElement(gs);
00313   
00314        // reset the graphics changes. this always represents a delta from previous state to current.
00315        mChanges = 0;
00316 
00317        return NS_OK;
00318 }
00319 
00320 //------------------------------------------------------------------------
00321 
00322 NS_IMETHODIMP nsRenderingContextMac::PopState(void)
00323 {
00324        NS_ASSERTION(ValidateDrawingState(), "Bad drawing state");
00325 
00326        PRInt32 count = mGSStack.Count();
00327        NS_ASSERTION(count > 0, "No state to pop");
00328        if (count > 0) {
00329               PRInt32 index = count - 1;
00330        
00331               // get the GS from the stack
00332               nsGraphicState* gs = (nsGraphicState *)mGSStack.ElementAt(index);
00333 
00334               // copy the GS into the current one and tell the current surface to use it
00335               mGS->Duplicate(gs);
00336               
00337               SelectDrawingSurface(mCurrentSurface, mChanges);
00338               
00339               // restore the current set of changes.
00340               mChanges = mGS->GetChanges();
00341 
00342               // remove the GS object from the stack and delete it
00343               mGSStack.RemoveElementAt(index);
00344               sGraphicStatePool.ReleaseGS(gs);
00345               
00346               // make sure the matrix is pointing at the current matrix
00347               mTranMatrix = &(mGS->mTMatrix);
00348        }
00349 
00350        return NS_OK;
00351 }
00352 
00353 #pragma mark -
00354 
00355 //------------------------------------------------------------------------
00356 
00357 NS_IMETHODIMP nsRenderingContextMac::LockDrawingSurface(PRInt32 aX, PRInt32 aY,
00358                                                           PRUint32 aWidth, PRUint32 aHeight,
00359                                                           void **aBits, PRInt32 *aStride,
00360                                                           PRInt32 *aWidthBytes, PRUint32 aFlags)
00361 {
00362   PushState();
00363 
00364   return mCurrentSurface->Lock(aX, aY, aWidth, aHeight,
00365                      aBits, aStride, aWidthBytes, aFlags);
00366 }
00367 
00368 //------------------------------------------------------------------------
00369 
00370 NS_IMETHODIMP nsRenderingContextMac::UnlockDrawingSurface(void)
00371 {
00372   PopState();
00373 
00374   mCurrentSurface->Unlock();
00375   
00376   return NS_OK;
00377 }
00378 
00379 //------------------------------------------------------------------------
00380 
00381 
00382 NS_IMETHODIMP nsRenderingContextMac::SelectOffScreenDrawingSurface(nsIDrawingSurface* aSurface)
00383 {  
00384        nsDrawingSurfaceMac* surface = static_cast<nsDrawingSurfaceMac*>(aSurface);
00385 
00386        if (surface != nsnull)
00387               SelectDrawingSurface(surface);                          // select the offscreen surface...
00388        else
00389               SelectDrawingSurface(mFrontSurface);             // ...or get back to the window port
00390 
00391        return NS_OK;
00392 }
00393 
00394 //------------------------------------------------------------------------
00395 
00396 NS_IMETHODIMP nsRenderingContextMac::GetDrawingSurface(nsIDrawingSurface* *aSurface)
00397 {  
00398        *aSurface = mCurrentSurface;
00399        // on Mac, select it too, to ensure that the port gets set correct for
00400        // tiling and image drawing
00401        //SelectDrawingSurface(mCurrentSurface);
00402        return NS_OK;
00403 }
00404 
00405 //------------------------------------------------------------------------
00406 
00407 NS_IMETHODIMP nsRenderingContextMac::CopyOffScreenBits(nsIDrawingSurface* aSrcSurf,
00408                                                          PRInt32 aSrcX, PRInt32 aSrcY,
00409                                                          const nsRect &aDestBounds,
00410                                                          PRUint32 aCopyFlags)
00411 {
00412        // hack: shortcut to bypass empty frames
00413        // or frames entirely recovered with other frames
00414        if ((aCopyFlags & NS_COPYBITS_TO_BACK_BUFFER) == 0)
00415               if (::EmptyRgn(mFrontSurface->GetGS()->mMainRegion))
00416                      return NS_OK;
00417 
00418        // retrieve the surface
00419        nsDrawingSurfaceMac* srcSurface = static_cast<nsDrawingSurfaceMac*>(aSrcSurf);
00420        CGrafPtr srcPort;
00421        srcSurface->GetGrafPtr(&srcPort);
00422 
00423        // apply the selected transformations
00424        PRInt32 x = aSrcX;
00425        PRInt32 y = aSrcY;
00426        if (aCopyFlags & NS_COPYBITS_XFORM_SOURCE_VALUES)
00427               mGS->mTMatrix.TransformCoord(&x, &y);
00428 
00429        nsRect dstRect = aDestBounds;
00430        if (aCopyFlags & NS_COPYBITS_XFORM_DEST_VALUES)
00431               mGS->mTMatrix.TransformCoord(&dstRect.x, &dstRect.y, &dstRect.width, &dstRect.height);
00432 
00433        // get the source and destination rectangles
00434        Rect macSrcRect, macDstRect;
00435        ::SetRect(&macSrcRect, x, y, x + dstRect.width, y + dstRect.height);
00436        ::SetRect(&macDstRect, dstRect.x, dstRect.y, dstRect.x + dstRect.width, dstRect.y + dstRect.height);
00437   
00438        // get the source clip region
00439        StRegionFromPool clipRgn;
00440        if (!clipRgn) return NS_ERROR_OUT_OF_MEMORY;
00441               
00442        if (aCopyFlags & NS_COPYBITS_USE_SOURCE_CLIP_REGION) {
00443               ::GetPortClipRegion(srcPort, clipRgn);
00444        } else
00445               ::CopyRgn(mGS->mMainRegion, clipRgn);
00446 
00447        // get the destination port and surface
00448        CGrafPtr destPort;
00449        nsDrawingSurfaceMac* destSurface;
00450        if (aCopyFlags & NS_COPYBITS_TO_BACK_BUFFER) {
00451               destSurface   = mCurrentSurface;
00452               destPort             = mPort;
00453               NS_ASSERTION((destPort != nsnull), "no back buffer");
00454        } else {
00455               destSurface   = mFrontSurface;
00456               mFrontSurface->GetGrafPtr(&destPort);
00457        }
00458 
00459   // we need to select the front surface so that the coordinates are set up correctly
00460   SelectDrawingSurface(destSurface);
00461   
00462        // set the right colors for CopyBits
00463        RGBColor foreColor;
00464        Boolean changedForeColor = false;
00465        ::GetForeColor(&foreColor);
00466        if ((foreColor.red != 0x0000) || (foreColor.green != 0x0000) || (foreColor.blue != 0x0000)) {
00467               RGBColor rgbBlack = {0x0000,0x0000,0x0000};
00468               ::RGBForeColor(&rgbBlack);
00469               changedForeColor = true;
00470        }
00471 
00472        RGBColor backColor;
00473        Boolean changedBackColor = false;
00474        ::GetBackColor(&backColor);
00475        if ((backColor.red != 0xFFFF) || (backColor.green != 0xFFFF) || (backColor.blue != 0xFFFF)) {
00476               RGBColor rgbWhite = {0xFFFF,0xFFFF,0xFFFF};
00477               ::RGBBackColor(&rgbWhite);
00478               changedBackColor = true;
00479        }
00480 
00481        // copy the bits now
00482        ::CopyBits(
00483           ::GetPortBitMapForCopyBits(srcPort),
00484           ::GetPortBitMapForCopyBits(destPort),
00485                 &macSrcRect,
00486                 &macDstRect,
00487                 srcCopy,
00488                 clipRgn);
00489 
00490        // restore colors and surface
00491        if (changedForeColor)
00492               ::RGBForeColor(&foreColor);
00493        if (changedBackColor)
00494               ::RGBBackColor(&backColor);
00495 
00496        return NS_OK;
00497 }
00498 
00499 //------------------------------------------------------------------------
00500 
00501 NS_IMETHODIMP nsRenderingContextMac::CreateDrawingSurface(const nsRect& aBounds, PRUint32 aSurfFlags, nsIDrawingSurface* &aSurface)
00502 {
00503        aSurface = nsnull;
00504 
00505        PRUint32 depth = 8;
00506        if (mContext)
00507               mContext->GetDepth(depth);
00508 
00509        // get rect
00510        Rect macRect;
00511   // fyi, aBounds->x and aBounds->y are always 0 here
00512   ::SetRect(&macRect, aBounds.x, aBounds.y, aBounds.XMost(), aBounds.YMost());
00513   
00514        nsDrawingSurfaceMac* surface = new nsDrawingSurfaceMac();
00515        if (!surface)
00516               return NS_ERROR_OUT_OF_MEMORY;
00517   NS_ADDREF(surface);
00518 
00519        nsresult rv = surface->Init(depth, macRect.right, macRect.bottom, aSurfFlags);
00520        if (NS_SUCCEEDED(rv))
00521               aSurface = surface;
00522        else
00523               delete surface;
00524 
00525        return rv;
00526 }
00527 
00528 //------------------------------------------------------------------------
00529 
00530 NS_IMETHODIMP nsRenderingContextMac::DestroyDrawingSurface(nsIDrawingSurface* aSurface)
00531 {
00532        if (!aSurface)
00533               return NS_ERROR_FAILURE;
00534 
00535        // if that surface is still the current one, select the front surface
00536        if (aSurface == mCurrentSurface)
00537        {
00538          NS_ASSERTION(mCurrentSurface != mFrontSurface, "Nuking the front surface");
00539               SelectDrawingSurface(mFrontSurface);
00540   }
00541        // release the surface
00542        nsDrawingSurfaceMac* surface = static_cast<nsDrawingSurfaceMac*>(aSurface);
00543        NS_IF_RELEASE(surface);
00544 
00545        return NS_OK;
00546 }
00547 
00548 
00549 #pragma mark -
00550 //------------------------------------------------------------------------
00551 
00552 NS_IMETHODIMP nsRenderingContextMac::GetHints(PRUint32& aResult)
00553 {
00554        PRUint32 result = 0;
00555 
00556        // QuickDraw is preferred over to ATSUI for drawing 7-bit text
00557        // (it's not 8-bit: the name of the constant is misleading)
00558        result |= NS_RENDERING_HINT_FAST_8BIT_TEXT;
00559        aResult = result;
00560        return NS_OK;
00561 }
00562 
00563 //------------------------------------------------------------------------
00564 
00565 NS_IMETHODIMP nsRenderingContextMac::Reset(void)
00566 {
00567        return NS_OK;
00568 }
00569 
00570 //------------------------------------------------------------------------
00571 
00572 NS_IMETHODIMP nsRenderingContextMac::GetDeviceContext(nsIDeviceContext *&aContext)
00573 {
00574        if (mContext) {
00575               aContext = mContext;
00576               NS_ADDREF(aContext);
00577        } else {
00578               aContext = nsnull;
00579        }
00580        return NS_OK;
00581 }
00582 
00583 //------------------------------------------------------------------------
00584 
00585 NS_IMETHODIMP nsRenderingContextMac::IsVisibleRect(const nsRect& aRect, PRBool &aVisible)
00586 {
00587        aVisible = PR_TRUE;
00588        return NS_OK;
00589 }
00590 
00591 //------------------------------------------------------------------------
00592 
00593 NS_IMETHODIMP nsRenderingContextMac::SetClipRect(const nsRect& aRect, nsClipCombine aCombine)
00594 {
00595        nsRect  trect = aRect;
00596 
00597        mGS->mTMatrix.TransformCoord(&trect.x, &trect.y, &trect.width, &trect.height);
00598 
00599        Rect macRect;
00600        ::SetRect(&macRect, trect.x, trect.y, trect.x + trect.width, trect.y + trect.height);
00601 
00602        StRegionFromPool rectRgn;
00603        RgnHandle clipRgn = mGS->mClipRegion;
00604        if (!clipRgn || !rectRgn)
00605               return NS_ERROR_OUT_OF_MEMORY;
00606 
00607        ::RectRgn(rectRgn, &macRect);
00608 
00609        switch (aCombine) {
00610        case nsClipCombine_kIntersect:
00611               ::SectRgn(clipRgn, rectRgn, clipRgn);
00612               break;
00613 
00614        case nsClipCombine_kUnion:
00615               ::UnionRgn(clipRgn, rectRgn, clipRgn);
00616               break;
00617 
00618        case nsClipCombine_kSubtract:
00619               ::DiffRgn(clipRgn, rectRgn, clipRgn);
00620               break;
00621 
00622        case nsClipCombine_kReplace:
00623 //     ::CopyRgn(rectRgn, clipRgn);
00624               ::SectRgn(rectRgn, mGS->mMainRegion, clipRgn);
00625               break;
00626        }
00627 
00628        {
00629               StPortSetter setter(mPort);
00630               ::SetClip(clipRgn);
00631        }
00632 
00633        mGS->mClipRegion = clipRgn;
00634        
00635        // note that the clipping changed.
00636        mChanges |= kClippingChanged;
00637 
00638        return NS_OK;
00639 }
00640 
00641 //------------------------------------------------------------------------
00642 
00643 NS_IMETHODIMP nsRenderingContextMac::GetClipRect(nsRect &aRect, PRBool &aClipValid)
00644 {
00645        Rect   cliprect;
00646 
00647        if (mGS->mClipRegion != nsnull) {
00648               ::GetRegionBounds(mGS->mClipRegion, &cliprect);
00649               aRect.SetRect(cliprect.left, cliprect.top, cliprect.right - cliprect.left, cliprect.bottom - cliprect.top);
00650               aClipValid = PR_TRUE;
00651        } else {
00652               aRect.SetRect(0,0,0,0);
00653               aClipValid = PR_FALSE;
00654        }
00655 
00656        return NS_OK;
00657 }
00658 
00659 //------------------------------------------------------------------------
00660 
00661 NS_IMETHODIMP nsRenderingContextMac::SetClipRegion(const nsIRegion& aRegion, nsClipCombine aCombine)
00662 {
00663        RgnHandle regionH;
00664        aRegion.GetNativeRegion((void*&)regionH);
00665 
00666        RgnHandle clipRgn = mGS->mClipRegion;
00667        if (!clipRgn) return NS_ERROR_OUT_OF_MEMORY;
00668 
00669        switch (aCombine) {
00670        case nsClipCombine_kIntersect:
00671               ::SectRgn(clipRgn, regionH, clipRgn);
00672               break;
00673 
00674        case nsClipCombine_kUnion:
00675               ::UnionRgn(clipRgn, regionH, clipRgn);
00676               break;
00677 
00678        case nsClipCombine_kSubtract:
00679               ::DiffRgn(clipRgn, regionH, clipRgn);
00680               break;
00681 
00682        case nsClipCombine_kReplace:
00683 //     ::CopyRgn(regionH, clipRgn);
00684               ::SectRgn(regionH, mGS->mMainRegion, clipRgn);
00685               break;
00686        }
00687 
00688               
00689        {
00690               StPortSetter setter(mPort);
00691               ::SetClip(clipRgn);
00692        }
00693 
00694        mGS->mClipRegion = clipRgn;
00695 
00696        // note that the clipping changed.
00697        mChanges |= kClippingChanged;
00698 
00699        return NS_OK;
00700 }
00701 
00705 NS_IMETHODIMP nsRenderingContextMac::CopyClipRegion(nsIRegion &aRegion)
00706 {
00707        nsRegionMac* macRegion = (nsRegionMac*)&aRegion;
00708        macRegion->SetNativeRegion(mGS->mClipRegion);
00709        return NS_OK;
00710 }
00711 
00712 //------------------------------------------------------------------------
00713 
00714 NS_IMETHODIMP nsRenderingContextMac::GetClipRegion(nsIRegion **aRegion)
00715 {
00716        nsresult  rv = NS_OK;
00717 
00718        NS_ASSERTION(!(nsnull == aRegion), "no region ptr");
00719 
00720        if (nsnull == *aRegion) {
00721               nsRegionMac *rgn = new nsRegionMac();
00722 
00723               if (nsnull != rgn) {
00724                      NS_ADDREF(rgn);
00725                      rv = rgn->Init();
00726 
00727                      if (NS_OK != rv)
00728                             NS_RELEASE(rgn);
00729                      else
00730                             *aRegion = rgn;
00731               } else
00732                      rv = NS_ERROR_OUT_OF_MEMORY;
00733        }
00734 
00735        if (rv == NS_OK) {
00736               nsRegionMac* macRegion = *(nsRegionMac**)aRegion;
00737               macRegion->SetNativeRegion(mGS->mClipRegion);
00738        }
00739 
00740        return rv;
00741 }
00742 
00743 //------------------------------------------------------------------------
00744 
00745 NS_IMETHODIMP nsRenderingContextMac::SetColor(nscolor aColor)
00746 {
00747        SetupPortState();
00748 
00749        #define COLOR8TOCOLOR16(color8)     ((color8 << 8) | color8)
00750 
00751        RGBColor color;
00752        color.red   = COLOR8TOCOLOR16(NS_GET_R(aColor));
00753        color.green = COLOR8TOCOLOR16(NS_GET_G(aColor));
00754        color.blue  = COLOR8TOCOLOR16(NS_GET_B(aColor));
00755        ::RGBForeColor(&color);
00756        mGS->mColor = aColor ;
00757 
00758        mChanges |= kColorChanged;
00759        
00760        return NS_OK;
00761 }
00762 
00763 //------------------------------------------------------------------------
00764 
00765 NS_IMETHODIMP nsRenderingContextMac::GetColor(nscolor &aColor) const
00766 {
00767        aColor = mGS->mColor;
00768        return NS_OK;
00769 }
00770 
00771 //------------------------------------------------------------------------
00772 
00773 NS_IMETHODIMP nsRenderingContextMac::SetLineStyle(nsLineStyle aLineStyle)
00774 {
00775   mGS->mLineStyle = aLineStyle;
00776   return NS_OK;
00777 }
00778 
00779 //------------------------------------------------------------------------
00780 
00781 NS_IMETHODIMP nsRenderingContextMac::GetLineStyle(nsLineStyle &aLineStyle)
00782 {
00783   aLineStyle = mGS->mLineStyle;
00784   return NS_OK;
00785 }
00786 
00787 
00788 //------------------------------------------------------------------------
00789 
00790 NS_IMETHODIMP nsRenderingContextMac::SetFont(const nsFont& aFont, nsIAtom* aLangGroup)
00791 {
00792        NS_IF_RELEASE(mGS->mFontMetrics);
00793 
00794        if (mContext)
00795               mContext->GetMetricsFor(aFont, aLangGroup, mGS->mFontMetrics);
00796 
00797        mChanges |= kFontChanged;
00798               
00799        return NS_OK;
00800 }
00801 
00802 //------------------------------------------------------------------------
00803 
00804 NS_IMETHODIMP nsRenderingContextMac::SetFont(nsIFontMetrics *aFontMetrics)
00805 {
00806        NS_IF_RELEASE(mGS->mFontMetrics);
00807        mGS->mFontMetrics = aFontMetrics;
00808        NS_IF_ADDREF(mGS->mFontMetrics);
00809        mChanges |= kFontChanged;
00810        return NS_OK;
00811 }
00812 
00813 //------------------------------------------------------------------------
00814 
00815 NS_IMETHODIMP nsRenderingContextMac::GetFontMetrics(nsIFontMetrics *&aFontMetrics)
00816 {
00817        NS_IF_ADDREF(mGS->mFontMetrics);
00818        aFontMetrics = mGS->mFontMetrics;
00819        return NS_OK;
00820 }
00821 
00822 //------------------------------------------------------------------------
00823 
00824 // add the passed in translation to the current translation
00825 NS_IMETHODIMP nsRenderingContextMac::Translate(nscoord aX, nscoord aY)
00826 {
00827        mGS->mTMatrix.AddTranslation((float)aX,(float)aY);
00828        return NS_OK;
00829 }
00830 
00831 //------------------------------------------------------------------------
00832 
00833 // add the passed in scale to the current scale
00834 NS_IMETHODIMP nsRenderingContextMac::Scale(float aSx, float aSy)
00835 {
00836        mGS->mTMatrix.AddScale(aSx, aSy);
00837        return NS_OK;
00838 }
00839 
00840 //------------------------------------------------------------------------
00841 
00842 NS_IMETHODIMP nsRenderingContextMac::GetCurrentTransform(nsTransform2D *&aTransform)
00843 {
00844        aTransform = &mGS->mTMatrix;
00845        return NS_OK;
00846 }
00847 
00848 
00849 #pragma mark -
00850 
00851 
00852 // 0 1 2 3 4 5 6 7
00853 // *   *   *   *  
00854 //   *   *   *   *
00855 // *   *   *   *  
00856 //   *   *   *   *
00857 // *   *   *   *  
00858 //   *   *   *   *
00859 // *   *   *   *  
00860 //   *   *   *   *
00861 static const Pattern dottedPattern = {0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55};
00862 
00863 // 0 1 2 3 4 5 6 7
00864 // * * * *        
00865 //   * * * *      
00866 //     * * * *    
00867 //       * * * *  
00868 //         * * * *
00869 // *         * * *
00870 // * *         * *
00871 // * * *         *
00872 static const Pattern dashedPattern = {0xf0,0x78,0x3c,0x1e,0x0f,0x87,0xc3,0xe1};
00873 
00874 //------------------------------------------------------------------------
00875 
00876 NS_IMETHODIMP nsRenderingContextMac::DrawLine(nscoord aX0, nscoord aY0, nscoord aX1, nscoord aY1)
00877 {
00878   if (mGS->mLineStyle == nsLineStyle_kNone)
00879     return NS_OK;
00880 
00881   SetupPortState();
00882 
00883   PenState savedPenState;
00884   RGBColor savedBGColor;
00885   if (mGS->mLineStyle == nsLineStyle_kDotted ||
00886       mGS->mLineStyle == nsLineStyle_kDashed) {
00887     ::GetPenState(&savedPenState);
00888     ::GetBackColor(&savedBGColor);
00889     
00890     ::PenMode(transparent);
00891     if (mGS->mLineStyle == nsLineStyle_kDashed)
00892       ::PenPat(&dashedPattern);
00893     else
00894       ::PenPat(&dottedPattern);
00895     RGBColor invertedForeColor;
00896     ::GetForeColor(&invertedForeColor);
00897     ::InvertColor(&invertedForeColor);
00898     ::RGBBackColor(&invertedForeColor);
00899   }
00900 
00901        mGS->mTMatrix.TransformCoord(&aX0,&aY0);
00902        mGS->mTMatrix.TransformCoord(&aX1,&aY1);
00903 
00904        // make the line one pixel shorter to match other platforms
00905        nscoord diffX = aX1 - aX0;
00906        if (diffX)
00907               diffX -= (diffX > 0 ? 1 : -1);
00908 
00909        nscoord diffY = aY1 - aY0;
00910        if (diffY)
00911               diffY -= (diffY > 0 ? 1 : -1);
00912 
00913        // draw line
00914        ::MoveTo(aX0, aY0);
00915        ::Line(diffX, diffY);
00916 
00917   if (mGS->mLineStyle == nsLineStyle_kDotted ||
00918       mGS->mLineStyle == nsLineStyle_kDashed) {
00919     ::PenMode(savedPenState.pnMode);
00920     ::PenPat(&savedPenState.pnPat);
00921     ::RGBBackColor(&savedBGColor);
00922   }
00923 
00924        return NS_OK;
00925 }
00926 
00927 
00928 //------------------------------------------------------------------------
00929 
00930 NS_IMETHODIMP nsRenderingContextMac::DrawPolyline(const nsPoint aPoints[], PRInt32 aNumPoints)
00931 {
00932   if (mGS->mLineStyle == nsLineStyle_kNone)
00933     return NS_OK;
00934 
00935        SetupPortState();
00936 
00937   PenState savedPenState;
00938   RGBColor savedBGColor;
00939   if (mGS->mLineStyle == nsLineStyle_kDotted ||
00940       mGS->mLineStyle == nsLineStyle_kDashed) {
00941     ::GetPenState(&savedPenState);
00942     ::GetBackColor(&savedBGColor);
00943     
00944     ::PenMode(transparent);
00945     if (mGS->mLineStyle == nsLineStyle_kDashed)
00946       ::PenPat(&dashedPattern);
00947     else
00948       ::PenPat(&dottedPattern);
00949     RGBColor invertedForeColor;
00950     ::GetForeColor(&invertedForeColor);
00951     ::InvertColor(&invertedForeColor);
00952     ::RGBBackColor(&invertedForeColor);
00953   }
00954 
00955        PRInt32    x,y;
00956 
00957        x = aPoints[0].x;
00958        y = aPoints[0].y;
00959        mGS->mTMatrix.TransformCoord((PRInt32*)&x,(PRInt32*)&y);
00960        ::MoveTo(x,y);
00961 
00962        for (PRInt32 i = 1; i < aNumPoints; i++)
00963        {
00964               x = aPoints[i].x;
00965               y = aPoints[i].y;
00966 
00967               mGS->mTMatrix.TransformCoord((PRInt32*)&x,(PRInt32*)&y);
00968               ::LineTo(x,y);
00969        }
00970 
00971   if (mGS->mLineStyle == nsLineStyle_kDotted ||
00972       mGS->mLineStyle == nsLineStyle_kDashed) {
00973     ::PenMode(savedPenState.pnMode);
00974     ::PenPat(&savedPenState.pnPat);
00975     ::RGBBackColor(&savedBGColor);
00976   }
00977 
00978        return NS_OK;
00979 }
00980 
00989        inline short pinToShort(nscoord value)
00990        {
00991               if (value < -32768)
00992                      return -32768;
00993               if (value > 32767)
00994                      return 32767;
00995               return (short) value;
00996        }
00997 
00998 
00999 //------------------------------------------------------------------------
01000 
01001 NS_IMETHODIMP nsRenderingContextMac::DrawRect(const nsRect& aRect)
01002 {
01003        return DrawRect(aRect.x, aRect.y, aRect.width, aRect.height);
01004 }
01005 
01006 //------------------------------------------------------------------------
01007 
01008 NS_IMETHODIMP nsRenderingContextMac::DrawRect(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight)
01009 {
01010        SetupPortState();
01011        
01012        nscoord x,y,w,h;
01013        Rect   therect;
01014 
01015        x = aX;
01016        y = aY;
01017        w = aWidth;
01018        h = aHeight;
01019 
01020        mGS->mTMatrix.TransformCoord(&x, &y, &w, &h);
01021        ::SetRect(&therect, pinToShort(x), pinToShort(y), pinToShort(x + w), pinToShort(y + h));
01022        ::FrameRect(&therect);
01023 
01024        return NS_OK;
01025 }
01026 
01027 //------------------------------------------------------------------------
01028 
01029 NS_IMETHODIMP nsRenderingContextMac::FillRect(const nsRect& aRect)
01030 {
01031        return FillRect(aRect.x, aRect.y, aRect.width, aRect.height);
01032 }
01033 
01034 //------------------------------------------------------------------------
01035 
01036 NS_IMETHODIMP nsRenderingContextMac::FillRect(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight)
01037 {
01038        SetupPortState();
01039 
01040        nscoord x,y,w,h;
01041        Rect   therect;
01042 
01043        x = aX;
01044        y = aY;
01045        w = aWidth;
01046        h = aHeight;
01047 
01048        // TODO - cps - must debug and fix this 
01049        mGS->mTMatrix.TransformCoord(&x, &y, &w, &h);
01050        ::SetRect(&therect, pinToShort(x), pinToShort(y), pinToShort(x + w), pinToShort(y + h));
01051        ::PaintRect(&therect);
01052 
01053        return NS_OK;
01054 }
01055 
01056 //------------------------------------------------------------------------
01057 
01058 NS_IMETHODIMP nsRenderingContextMac::DrawPolygon(const nsPoint aPoints[], PRInt32 aNumPoints)
01059 {
01060        SetupPortState();
01061 
01062        PolyHandle thepoly;
01063        PRInt32    x,y;
01064 
01065        thepoly = ::OpenPoly();
01066        if (nsnull == thepoly) {
01067               return NS_ERROR_OUT_OF_MEMORY;
01068        }
01069 
01070        x = aPoints[0].x;
01071        y = aPoints[0].y;
01072        mGS->mTMatrix.TransformCoord((PRInt32*)&x,(PRInt32*)&y);
01073        ::MoveTo(x,y);
01074 
01075        for (PRInt32 i = 1; i < aNumPoints; i++) {
01076               x = aPoints[i].x;
01077               y = aPoints[i].y;
01078               
01079               mGS->mTMatrix.TransformCoord((PRInt32*)&x,(PRInt32*)&y);
01080               ::LineTo(x,y);
01081        }
01082 
01083        ::ClosePoly();
01084 
01085        ::FramePoly(thepoly);
01086        ::KillPoly(thepoly);
01087 
01088        return NS_OK;
01089 }
01090 
01091 //------------------------------------------------------------------------
01092 
01093 NS_IMETHODIMP nsRenderingContextMac::FillPolygon(const nsPoint aPoints[], PRInt32 aNumPoints)
01094 {
01095        SetupPortState();
01096 
01097        PolyHandle thepoly;
01098        PRInt32    x,y;
01099 
01100        thepoly = ::OpenPoly();
01101        if (nsnull == thepoly) {
01102               return NS_ERROR_OUT_OF_MEMORY;
01103        }
01104 
01105        x = aPoints[0].x;
01106        y = aPoints[0].y;
01107        mGS->mTMatrix.TransformCoord((PRInt32*)&x,(PRInt32*)&y);
01108        ::MoveTo(x,y);
01109 
01110        for (PRInt32 i = 1; i < aNumPoints; i++) {
01111               x = aPoints[i].x;
01112               y = aPoints[i].y;
01113               mGS->mTMatrix.TransformCoord((PRInt32*)&x,(PRInt32*)&y);
01114               ::LineTo(x,y);
01115        }
01116 
01117        ::ClosePoly();
01118        ::PaintPoly(thepoly);
01119        ::KillPoly(thepoly);
01120 
01121        return NS_OK;
01122 }
01123 
01124 //------------------------------------------------------------------------
01125 
01126 NS_IMETHODIMP nsRenderingContextMac::DrawEllipse(const nsRect& aRect)
01127 {
01128        return DrawEllipse(aRect.x, aRect.y, aRect.width, aRect.height);
01129 }
01130 
01131 //------------------------------------------------------------------------
01132 
01133 NS_IMETHODIMP nsRenderingContextMac::DrawEllipse(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight)
01134 {
01135        SetupPortState();
01136 
01137        nscoord x,y,w,h;
01138        Rect    therect;
01139 
01140        x = aX;
01141        y = aY;
01142        w = aWidth;
01143        h = aHeight;
01144 
01145        mGS->mTMatrix.TransformCoord(&x,&y,&w,&h);
01146        ::SetRect(&therect, pinToShort(x), pinToShort(y), pinToShort(x + w), pinToShort(y + h));
01147        ::FrameOval(&therect);
01148 
01149        return NS_OK;
01150 }
01151 
01152 //------------------------------------------------------------------------
01153 
01154 NS_IMETHODIMP nsRenderingContextMac::FillEllipse(const nsRect& aRect)
01155 {
01156        return FillEllipse(aRect.x, aRect.y, aRect.width, aRect.height);
01157 }
01158 
01159 //------------------------------------------------------------------------
01160 
01161 NS_IMETHODIMP nsRenderingContextMac::FillEllipse(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight)
01162 {
01163        SetupPortState();
01164 
01165        nscoord x,y,w,h;
01166        Rect    therect;
01167 
01168        x = aX;
01169        y = aY;
01170        w = aWidth;
01171        h = aHeight;
01172 
01173        mGS->mTMatrix.TransformCoord(&x,&y,&w,&h);
01174        ::SetRect(&therect, pinToShort(x), pinToShort(y), pinToShort(x + w), pinToShort(y + h));
01175        ::PaintOval(&therect);
01176 
01177        return NS_OK;
01178 }
01179 
01180 //------------------------------------------------------------------------
01181 
01182 NS_IMETHODIMP nsRenderingContextMac::DrawArc(const nsRect& aRect,
01183                                  float aStartAngle, float aEndAngle)
01184 {
01185        return DrawArc(aRect.x,aRect.y,aRect.width,aRect.height,aStartAngle,aEndAngle);
01186 }
01187 
01188 //------------------------------------------------------------------------
01189 
01190 NS_IMETHODIMP nsRenderingContextMac::DrawArc(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight,
01191                                  float aStartAngle, float aEndAngle)
01192 {
01193        SetupPortState();
01194 
01195        nscoord x,y,w,h;
01196        Rect    therect;
01197 
01198        x = aX;
01199        y = aY;
01200        w = aWidth;
01201        h = aHeight;
01202 
01203        mGS->mTMatrix.TransformCoord(&x,&y,&w,&h);
01204        ::SetRect(&therect, pinToShort(x), pinToShort(y), pinToShort(x + w), pinToShort(y + h));
01205        ::FrameArc(&therect, (short)aStartAngle, (short)aEndAngle);
01206 
01207        return NS_OK;
01208 }
01209 
01210 //------------------------------------------------------------------------
01211 
01212 NS_IMETHODIMP nsRenderingContextMac::FillArc(const nsRect& aRect,
01213                                  float aStartAngle, float aEndAngle)
01214 {
01215        return FillArc(aRect.x, aRect.y, aRect.width, aRect.height, aStartAngle, aEndAngle);
01216 }
01217 
01218 //------------------------------------------------------------------------
01219 
01220 NS_IMETHODIMP nsRenderingContextMac::FillArc(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight,
01221                                  float aStartAngle, float aEndAngle)
01222 {
01223        SetupPortState();
01224 
01225        nscoord x,y,w,h;
01226        Rect   therect;
01227 
01228        x = aX;
01229        y = aY;
01230        w = aWidth;
01231        h = aHeight;
01232 
01233        mGS->mTMatrix.TransformCoord(&x,&y,&w,&h);
01234        ::SetRect(&therect, pinToShort(x), pinToShort(y), pinToShort(x + w), pinToShort(y + h));
01235        ::PaintArc(&therect, (short)aStartAngle, (short)aEndAngle);
01236 
01237        return NS_OK;
01238 }
01239 
01240 #pragma mark -
01241 
01242 PRInt32 nsRenderingContextMac::GetMaxStringLength()
01243 {
01244   if (!mGS->mFontMetrics)
01245     return 1;
01246   return NS_STATIC_CAST(nsFontMetricsMac*, mGS->mFontMetrics)->GetMaxStringLength();
01247 }
01248 
01249 //------------------------------------------------------------------------
01250 
01251 NS_IMETHODIMP nsRenderingContextMac::GetWidth(char ch, nscoord &aWidth)
01252 {
01253        if (ch == ' ' && mGS->mFontMetrics) {
01254               return mGS->mFontMetrics->GetSpaceWidth(aWidth);
01255        }
01256 
01257        char buf[1];
01258        buf[0] = ch;
01259        return GetWidth(buf, 1, aWidth);
01260 }
01261 
01262 //------------------------------------------------------------------------
01263 
01264 NS_IMETHODIMP nsRenderingContextMac::GetWidth(PRUnichar ch, nscoord &aWidth, PRInt32 *aFontID)
01265 {
01266        if (ch == ' ' && mGS->mFontMetrics) {
01267               return mGS->mFontMetrics->GetSpaceWidth(aWidth);
01268        }
01269 
01270        PRUnichar buf[1];
01271        buf[0] = ch;
01272        return GetWidth(buf, 1, aWidth, aFontID);
01273 }
01274 
01275 //------------------------------------------------------------------------
01276 
01277 NS_IMETHODIMP
01278 nsRenderingContextMac::GetWidthInternal(const char* aString, PRUint32 aLength, nscoord& aWidth)
01279 {
01280        SetupPortState();
01281 
01282        // set native font and attributes
01283        SetPortTextState();
01284 
01285 //   below is a bad assert, aString is not guaranteed null terminated...
01286 //    NS_ASSERTION(strlen(aString) >= aLength, "Getting width on garbage string");
01287   
01288        // measure text
01289        short textWidth = ::TextWidth(aString, 0, aLength);
01290        aWidth = NSToCoordRound(float(textWidth) * mP2T);
01291 
01292        return NS_OK;
01293 }
01294 
01295 //------------------------------------------------------------------------
01296 
01297 NS_IMETHODIMP
01298 nsRenderingContextMac::GetWidthInternal(const PRUnichar *aString, PRUint32 aLength, nscoord &aWidth, PRInt32 *aFontID)
01299 {
01300        SetupPortState();
01301        
01302        nsresult rv = SetPortTextState();
01303        if (NS_FAILED(rv))
01304               return rv;
01305 
01306   PRBool rtlText = mRightToLeftText;
01307 
01308        rv = mUnicodeRenderingToolkit.PrepareToDraw(mP2T, mContext, mGS, mPort, rtlText);
01309        if (NS_SUCCEEDED(rv))
01310     rv = mUnicodeRenderingToolkit.GetWidth(aString, aLength, aWidth, aFontID);
01311     
01312        return rv;
01313 }
01314 
01315 //------------------------------------------------------------------------
01316 
01317 NS_IMETHODIMP
01318 nsRenderingContextMac::GetTextDimensionsInternal(const char* aString, PRUint32 aLength,
01319                                                  nsTextDimensions& aDimensions)
01320 {
01321   nsresult rv= GetWidth(aString, aLength, aDimensions.width);
01322   if (NS_SUCCEEDED(rv) && (mGS->mFontMetrics))
01323   {
01324     mGS->mFontMetrics->GetMaxAscent(aDimensions.ascent);
01325     mGS->mFontMetrics->GetMaxDescent(aDimensions.descent);
01326   }
01327   return rv;
01328 }
01329 
01330 NS_IMETHODIMP
01331 nsRenderingContextMac::GetTextDimensionsInternal(const PRUnichar* aString, PRUint32 aLength,
01332                                                  nsTextDimensions& aDimensions, PRInt32* aFontID)
01333 {
01334   SetupPortState();
01335   
01336   nsresult rv = SetPortTextState();
01337   if (NS_FAILED(rv))
01338     return rv;
01339 
01340   PRBool rtlText = mRightToLeftText;
01341 
01342   rv = mUnicodeRenderingToolkit.PrepareToDraw(mP2T, mContext, mGS, mPort, rtlText);
01343        if (NS_SUCCEEDED(rv))
01344     rv = mUnicodeRenderingToolkit.GetTextDimensions(aString, aLength, aDimensions, aFontID);
01345     
01346   return rv;
01347 }
01348 
01349 #pragma mark -
01350 //------------------------------------------------------------------------
01351 
01352 NS_IMETHODIMP nsRenderingContextMac::DrawStringInternal(const char *aString, PRUint32 aLength,
01353                                                         nscoord aX, nscoord aY,
01354                                                         const nscoord* aSpacing)
01355 {
01356        SetupPortState();
01357 
01358        PRInt32 x = aX;
01359        PRInt32 y = aY;
01360        
01361        if (mGS->mFontMetrics) {
01362               // set native font and attributes
01363               SetPortTextState();
01364        }
01365 
01366        mGS->mTMatrix.TransformCoord(&x,&y);
01367 
01368        ::MoveTo(x,y);
01369        if ( aSpacing == NULL )
01370               ::DrawText(aString,0,aLength);
01371        else
01372        {
01373               int buffer[STACK_THRESHOLD];
01374               int* spacing = (aLength <= STACK_THRESHOLD ? buffer : new int[aLength]);
01375               if (spacing)
01376               {
01377                      mGS->mTMatrix.ScaleXCoords(aSpacing, aLength, spacing);
01378                      PRInt32 currentX = x;
01379                      for (PRUint32 i = 0; i < aLength; i++)
01380                      {
01381                             ::DrawChar(aString[i]);
01382                             currentX += spacing[i];
01383                             ::MoveTo(currentX, y);
01384                      }
01385                      if (spacing != buffer)
01386                             delete[] spacing;
01387               }
01388               else
01389                      return NS_ERROR_OUT_OF_MEMORY;
01390        }
01391 
01392        return NS_OK;
01393 }
01394 
01395 
01396 
01397 
01398 //------------------------------------------------------------------------
01399 NS_IMETHODIMP nsRenderingContextMac::DrawStringInternal(const PRUnichar *aString, PRUint32 aLength,
01400                                                         nscoord aX, nscoord aY, PRInt32 aFontID,
01401                                                         const nscoord* aSpacing)
01402 {
01403        SetupPortState();
01404 
01405        nsresult rv = SetPortTextState();
01406        if (NS_FAILED(rv))
01407               return rv;
01408 
01409        NS_PRECONDITION(mGS->mFontMetrics != nsnull, "No font metrics in SetPortTextState");
01410        
01411        if (nsnull == mGS->mFontMetrics)
01412               return NS_ERROR_NULL_POINTER;
01413 
01414   PRBool rtlText = mRightToLeftText;
01415 
01416        rv = mUnicodeRenderingToolkit.PrepareToDraw(mP2T, mContext, mGS, mPort, rtlText);
01417        if (NS_SUCCEEDED(rv))
01418               rv = mUnicodeRenderingToolkit.DrawString(aString, aLength, aX, aY, aFontID, aSpacing);
01419 
01420        return rv;        
01421 }
01422 
01423 #pragma mark -
01424 //------------------------------------------------------------------------
01425 
01426 NS_IMETHODIMP nsRenderingContextMac::RetrieveCurrentNativeGraphicData(void** ngd)
01427 {
01428   return NS_OK;
01429 }
01430 
01431 NS_IMETHODIMP nsRenderingContextMac::InvertRect(const nsRect& aRect)
01432 {
01433        return InvertRect(aRect.x, aRect.y, aRect.width, aRect.height);
01434 }
01435 
01436 NS_IMETHODIMP nsRenderingContextMac::InvertRect(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight)
01437 {
01438        SetupPortState();
01439 
01440        nscoord x,y,w,h;
01441        Rect   therect;
01442 
01443        x = aX;
01444        y = aY;
01445        w = aWidth;
01446        h = aHeight;
01447 
01448        mGS->mTMatrix.TransformCoord(&x, &y, &w, &h);
01449        ::SetRect(&therect, pinToShort(x), pinToShort(y), pinToShort(x + w), pinToShort(y + h));
01450        ::InvertRect(&therect);
01451 
01452        return NS_OK;
01453 }
01454 
01455 NS_IMETHODIMP
01456 nsRenderingContextMac::FlushRect(const nsRect& aRect)
01457 {
01458   return FlushRect(aRect.x, aRect.y, aRect.width, aRect.height);
01459 }
01460 
01461 NS_IMETHODIMP
01462 nsRenderingContextMac::FlushRect(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight)
01463 {
01464 #ifdef MOZ_WIDGET_COCOA
01465   if (mPort) {
01466     SetupPortState();
01467 
01468     nscoord x,y,w,h;
01469 
01470     x = aX;
01471     y = aY;
01472     w = aWidth;
01473     h = aHeight;
01474 
01475     mGS->mTMatrix.TransformCoord(&x, &y, &w, &h);
01476 
01477     StRegionFromPool rgn;
01478     if (!rgn) return NS_ERROR_OUT_OF_MEMORY;
01479 
01480     ::SetRectRgn(rgn, pinToShort(x), pinToShort(y), pinToShort(x + w), pinToShort(y + h));
01481 
01482     nsCOMPtr<nsIQDFlushManager> qdFlushManager =
01483      do_GetService("@mozilla.org/gfx/qdflushmanager;1");
01484     if (qdFlushManager)
01485       qdFlushManager->FlushPortBuffer(mPort, rgn);
01486   }
01487 #endif
01488   return NS_OK;
01489 }
01490 
01491 #ifdef MOZ_MATHML
01492 
01493 NS_IMETHODIMP
01494 nsRenderingContextMac::GetBoundingMetricsInternal(const char*        aString, 
01495                                                   PRUint32           aLength,
01496                                                   nsBoundingMetrics& aBoundingMetrics)
01497 {
01498   return NS_ERROR_NOT_IMPLEMENTED;
01499 }
01500 
01501 NS_IMETHODIMP
01502 nsRenderingContextMac::GetBoundingMetricsInternal(const PRUnichar*   aString, 
01503                                                   PRUint32           aLength,
01504                                                   nsBoundingMetrics& aBoundingMetrics,
01505                                                   PRInt32*           aFontID)
01506 {
01507   SetupPortState();
01508   
01509   nsresult rv = SetPortTextState();
01510   if(NS_FAILED(rv))
01511     return rv;
01512   
01513   PRBool rtlText = mRightToLeftText;
01514 
01515   rv = mUnicodeRenderingToolkit.PrepareToDraw(mP2T, mContext, mGS, mPort, rtlText);
01516   if(NS_SUCCEEDED(rv))
01517     rv = mUnicodeRenderingToolkit.GetTextBoundingMetrics(aString, aLength, aBoundingMetrics, aFontID);
01518   
01519   return rv;
01520 }
01521 
01522 
01523 #endif /* MOZ_MATHML */
01524 
01525 
01526 NS_IMETHODIMP
01527 nsRenderingContextMac::SetRightToLeftText(PRBool aIsRTL)
01528 {
01529   mRightToLeftText = aIsRTL;
01530        return NS_OK;
01531 }
01532 
01533 NS_IMETHODIMP
01534 nsRenderingContextMac::GetRightToLeftText(PRBool* aIsRTL)
01535 {
01536   *aIsRTL = mRightToLeftText;
01537   return NS_OK;
01538 }
01539 
01540 NS_IMETHODIMP
01541 nsRenderingContextMac::DrawImage(imgIContainer *aImage, const nsRect & aSrcRect, const nsRect & aDestRect)
01542 {
01543   SetupPortState();
01544   return nsRenderingContextImpl::DrawImage(aImage, aSrcRect, aDestRect);
01545 }
01546 
01547 NS_IMETHODIMP
01548 nsRenderingContextMac::DrawTile(imgIContainer *aImage,
01549                     nscoord aXImageStart, nscoord aYImageStart,
01550                     const nsRect * aTargetRect)
01551 {
01552   SetupPortState();
01553   return nsRenderingContextImpl::DrawTile(aImage, aXImageStart, aYImageStart, aTargetRect);
01554 }
01555 
01556 #pragma mark -
01557 
01558 // override to set the port back to the window port
01559 NS_IMETHODIMP
01560 nsRenderingContextMac::ReleaseBackbuffer(void)
01561 {
01562   SelectOffScreenDrawingSurface(nsnull);
01563   return NS_OK;
01564 }
01565 
01566 
01567 // override to not use a back buffer on MacOS X
01568 NS_IMETHODIMP 
01569 nsRenderingContextMac::UseBackbuffer(PRBool* aUseBackbuffer)
01570 {
01571   *aUseBackbuffer = PR_FALSE;
01572   return NS_OK;
01573 }
01574 
01575 
01576 PRBool
01577 nsRenderingContextMac::OnTigerOrLater()
01578 {
01579   static PRBool sInitVer = PR_FALSE;
01580   static PRBool sOnTigerOrLater = PR_FALSE;
01581   if (!sInitVer) {
01582     long version;
01583     OSErr err = ::Gestalt(gestaltSystemVersion, &version);
01584     sOnTigerOrLater = ((err == noErr) && (version >= 0x00001040));
01585     sInitVer = PR_TRUE;
01586   }
01587   return sOnTigerOrLater;
01588 }