Back to index

lightning-sunbird  0.9+nobinonly
nsRenderingContextPh.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either of the GNU General Public License Version 2 or later (the "GPL"),
00026  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #include "nsFontMetricsPh.h"
00039 #include "nsGraphicsStatePh.h"
00040 #include "nsGfxCIID.h"
00041 #include "nsRegionPh.h"
00042 #include "nsRenderingContextPh.h"
00043 #include "nsICharRepresentable.h"
00044 #include "nsDeviceContextPh.h"
00045 #include "prprf.h"
00046 #include "nsDrawingSurfacePh.h"
00047 
00048 #include <stdlib.h>
00049 #include <mem.h>
00050 #include "nsReadableUtils.h"
00051 
00052 static NS_DEFINE_CID(kRegionCID, NS_REGION_CID);
00053 
00054 
00055 #include <prlog.h>
00056 PRLogModuleInfo *PhGfxLog = PR_NewLogModule("PhGfxLog");
00057 #include "nsPhGfxLog.h"
00058 
00059 NS_IMPL_ISUPPORTS1(nsRenderingContextPh, nsIRenderingContext)
00060 
00061 
00062 static unsigned char sLineStyle[4][2] =
00063   {
00064   { 0 },      /* nsLineStyle_kNone */
00065   { 0 },      /* nsLineStyle_kSolid */
00066   { 10, 4 },  /* nsLineStyle_kDashed */
00067   { 1 }                            /* nsLineStyle_kDotted */
00068   };
00069 
00070 static unsigned char sLineStyleLen[4] =
00071   {
00072   0,        /* nsLineStyle_kNone */
00073   0,      /* nsLineStyle_kSolid */
00074   2,      /* nsLineStyle_kDashed */
00075   1       /* nsLineStyle_kDotted */
00076   };
00077 
00078 nsRenderingContextPh :: nsRenderingContextPh() 
00079 {
00080        mGC               = nsnull;
00081        mTranMatrix       = nsnull;
00082        mClipRegion       = nsnull;
00083        mFontMetrics      = nsnull;
00084        mSurface          = nsnull;
00085        mOffscreenSurface = nsnull;
00086        mContext          = nsnull;
00087        mP2T              = 1.0f;
00088        mPhotonFontName   = nsnull;
00089        mCurrentColor     = NS_RGB(255, 255, 255);
00090        mCurrentLineStyle = nsLineStyle_kSolid;
00091        mStateCache       = new nsVoidArray();
00092        mOwner                                    = PR_FALSE;
00093        
00094        PushState();
00095 }
00096 
00097 nsRenderingContextPh :: ~nsRenderingContextPh() 
00098 {
00099 
00100        // Destroy the State Machine
00101        if( mStateCache ) {
00102          PRInt32 cnt = mStateCache->Count();
00103               
00104               while( cnt > 0 ) {
00105                      /* because PopState() is, besides freeing the state, also applying it, we can avoid calling PopState() here */
00106                      /* and instead, release the state explicitely */
00107                      nsGraphicsState *state = (nsGraphicsState *)mStateCache->ElementAt(cnt - 1);
00108                      mStateCache->RemoveElementAt(cnt - 1);
00109                      if ( state->mMatrix) delete state->mMatrix;
00110               
00111        // Delete this graphics state object
00112 #ifdef USE_GS_POOL
00113        nsGraphicsStatePool::ReleaseGS(state);
00114 #else
00115        delete state;
00116 #endif 
00117                      cnt--;
00118               }
00119               delete mStateCache;
00120               mStateCache = nsnull;
00121        }
00122 
00123        if( mTranMatrix ) 
00124               delete mTranMatrix;
00125        
00126        NS_IF_RELEASE( mOffscreenSurface );              /* this also clears mSurface.. or should */
00127        NS_IF_RELEASE( mFontMetrics );
00128        NS_IF_RELEASE( mContext );
00129 
00130        /* Go back to the default Photon DrawContext */
00131        PgSetGC( NULL );
00132 
00133        if( mPhotonFontName ) 
00134               delete [] mPhotonFontName;
00135 
00136        if( mOwner ) {
00137               PgDestroyGC( mGC );
00138               }
00139 }
00140 
00141 
00142 NS_IMETHODIMP nsRenderingContextPh :: Init( nsIDeviceContext* aContext, nsIWidget *aWindow ) 
00143 {
00144        nsresult res;
00145        
00146        mContext = aContext;
00147        NS_IF_ADDREF(mContext);
00148        
00149        PtWidget_t *widget = (PtWidget_t*) aWindow->GetNativeData( NS_NATIVE_WIDGET );
00150        
00151        if( !widget ) {
00152               NS_IF_RELEASE( mContext ); // new
00153               NS_ASSERTION(widget,"nsRenderingContext::Init (with a widget) widget is NULL!");
00154               return NS_ERROR_FAILURE;
00155        }
00156        
00157        mRegionID = PtWidgetRid( widget );
00158        if( mRegionID ) {
00159               mSurface = new nsDrawingSurfacePh();
00160               if( mSurface ) {
00161 
00162                      mGC = PgCreateGC( 0 );
00163                      mOwner = PR_TRUE;
00164 
00165                      /* use the dc you get by doing a PhDCSetCurrent( NULL ) */
00166                      res = mSurface->Init( _Ph_->dflt_draw_context, mGC );
00167                      if( res != NS_OK )
00168                             return NS_ERROR_FAILURE;
00169                      
00170                      mOffscreenSurface = mSurface;
00171                      NS_ADDREF( mSurface );
00172 
00173                      mSurfaceDC = ((nsDrawingSurfacePh*)mSurface)->GetDC();
00174               }
00175               else 
00176                      return NS_ERROR_FAILURE;
00177        }
00178 
00179        return CommonInit();
00180 }
00181 
00182 NS_IMETHODIMP nsRenderingContextPh :: PushState( void ) 
00183 {
00184        //  Get a new GS
00185 #ifdef USE_GS_POOL
00186        nsGraphicsState *state = nsGraphicsStatePool::GetNewGS();
00187 #else
00188        nsGraphicsState *state = new nsGraphicsState;
00189 #endif
00190 
00191        // Push into this state object, add to vector
00192        if( !state ) {
00193               NS_ASSERTION(0, "nsRenderingContextPh::PushState Failed to create a new Graphics State");
00194               return NS_ERROR_FAILURE;
00195        }
00196        
00197        state->mMatrix = mTranMatrix;
00198        
00199        if( nsnull == mTranMatrix ) 
00200               mTranMatrix = new nsTransform2D();
00201        else 
00202               mTranMatrix = new nsTransform2D(mTranMatrix);
00203        
00204        // set the state's clip region to a new copy of the current clip region
00205        //  if( mClipRegion ) GetClipRegion( &state->mClipRegion );
00206        state->mClipRegion = mClipRegion;
00207 
00208        NS_IF_ADDREF(mFontMetrics);
00209        state->mFontMetrics = mFontMetrics;
00210        
00211        state->mColor = mCurrentColor;
00212        state->mLineStyle = mCurrentLineStyle;
00213        
00214        mStateCache->AppendElement(state);
00215        
00216        return NS_OK;
00217 }
00218 
00219 NS_IMETHODIMP nsRenderingContextPh :: PopState(void) 
00220 {
00221        PRUint32 cnt = mStateCache->Count();
00222        nsGraphicsState * state;
00223        
00224        if (cnt > 0) {
00225               state = (nsGraphicsState *)mStateCache->ElementAt(cnt - 1);
00226               mStateCache->RemoveElementAt(cnt - 1);
00227               
00228               // Assign all local attributes from the state object just popped
00229               if ( state->mMatrix) {
00230                      if (mTranMatrix)
00231                             delete mTranMatrix;
00232                      mTranMatrix = state->mMatrix;
00233               }
00234               
00235               // restore everything
00236               mClipRegion = state->mClipRegion;
00237 
00238               if( state->mFontMetrics && mFontMetrics != state->mFontMetrics ) 
00239                      SetFont( state->mFontMetrics );
00240               
00241               //    if( mSurface && mClipRegion ) ApplyClipping( mGC );
00242               mCurrentColor = state->mColor;
00243               mCurrentLineStyle = state->mLineStyle;
00244               
00245               // Delete this graphics state object
00246 #ifdef USE_GS_POOL
00247               nsGraphicsStatePool::ReleaseGS(state);
00248 #else
00249               delete state;
00250 #endif
00251        }
00252        
00253        return NS_OK;
00254 }
00255 
00256 
00257 NS_IMETHODIMP nsRenderingContextPh :: GetClipRect( nsRect &aRect, PRBool &aClipValid ) 
00258 {
00259        PRInt32 x, y, w, h;
00260        
00261        if ( !mClipRegion )
00262               return NS_ERROR_FAILURE;
00263        
00264        if( !mClipRegion->IsEmpty() ) {
00265               mClipRegion->GetBoundingBox( &x, &y, &w, &h );
00266               aRect.SetRect( x, y, w, h );
00267               aClipValid = PR_TRUE;
00268        }
00269        else {
00270               aRect.SetRect(0,0,0,0);
00271               aClipValid = PR_FALSE;
00272        }
00273        return NS_OK;
00274 }
00275 
00276 NS_IMETHODIMP nsRenderingContextPh :: SetClipRect( const nsRect& aRect, nsClipCombine aCombine ) 
00277 {
00278        nsresult   res = NS_ERROR_FAILURE;
00279        nsRect     trect = aRect;
00280        PRUint32 cnt = mStateCache->Count();
00281        nsGraphicsState *state = nsnull;
00282        
00283        if (cnt > 0) {
00284               state = (nsGraphicsState *)mStateCache->ElementAt(cnt - 1);
00285        }
00286        
00287        if (state) {
00288               if (state->mClipRegion) {
00289                      if (state->mClipRegion == mClipRegion) {
00290                             nsCOMPtr<nsIRegion> tmpRgn;
00291                             GetClipRegion(getter_AddRefs(tmpRgn));
00292                             mClipRegion = tmpRgn;
00293                      }
00294               }
00295        }
00296        
00297        /* create clip region ( CreateClipRegion ) */
00298   if( !mClipRegion ) {
00299     PRUint32 w, h;
00300     mSurface->GetSize(&w, &h);
00301 
00302     mClipRegion = do_CreateInstance(kRegionCID);
00303     if( mClipRegion ) {
00304       mClipRegion->Init();
00305       mClipRegion->SetTo(0,0,w,h);
00306       }
00307     }
00308        
00309        if( mTranMatrix && mClipRegion ) {
00310               mTranMatrix->TransformCoord( &trect.x, &trect.y,&trect.width, &trect.height );
00311               switch( aCombine ) {
00312                      case nsClipCombine_kIntersect:
00313                             mClipRegion->Intersect(trect.x,trect.y,trect.width,trect.height);
00314                             break;
00315                      case nsClipCombine_kUnion:
00316                             mClipRegion->Union(trect.x,trect.y,trect.width,trect.height);
00317                             break;
00318                      case nsClipCombine_kSubtract:
00319                             mClipRegion->Subtract(trect.x,trect.y,trect.width,trect.height);
00320                             break;
00321                      case nsClipCombine_kReplace:
00322                             mClipRegion->SetTo(trect.x,trect.y,trect.width,trect.height);
00323                             break;
00324                      default:
00325                             break;
00326               }
00327               
00328               res = NS_OK;
00329        }
00330        
00331        return res;
00332 }
00333 
00334 NS_IMETHODIMP nsRenderingContextPh :: SetClipRegion( const nsIRegion& aRegion, nsClipCombine aCombine ) 
00335 {
00336        PRUint32 cnt = mStateCache->Count();
00337        nsGraphicsState *state = nsnull;
00338        
00339        if (cnt > 0) {
00340               state = (nsGraphicsState *)mStateCache->ElementAt(cnt - 1);
00341        }
00342        
00343        if (state) {
00344               if (state->mClipRegion) {
00345                      if (state->mClipRegion == mClipRegion) {
00346                             nsCOMPtr<nsIRegion> tmpRgn;
00347                             GetClipRegion(getter_AddRefs(tmpRgn));
00348                             mClipRegion = tmpRgn;
00349                      }
00350               }
00351        }
00352        
00353        /* create clip region ( CreateClipRegion ) */
00354   if( !mClipRegion ) {
00355     PRUint32 w, h;
00356     mSurface->GetSize(&w, &h);
00357 
00358     mClipRegion = do_CreateInstance(kRegionCID);
00359     if( mClipRegion ) {
00360       mClipRegion->Init();
00361       mClipRegion->SetTo(0,0,w,h);
00362       }
00363     }
00364        
00365        switch( aCombine ) {
00366               case nsClipCombine_kIntersect:
00367                      mClipRegion->Intersect(aRegion);
00368                      break;
00369               case nsClipCombine_kUnion:
00370                      mClipRegion->Union(aRegion);
00371                      break;
00372               case nsClipCombine_kSubtract:
00373                      mClipRegion->Subtract(aRegion);
00374                      break;
00375               case nsClipCombine_kReplace:
00376                      mClipRegion->SetTo(aRegion);
00377                      break;
00378        }
00379        
00380        return NS_OK;
00381 }
00382 
00383 NS_IMETHODIMP nsRenderingContextPh :: GetClipRegion( nsIRegion **aRegion ) 
00384 {
00385        nsresult rv = NS_ERROR_FAILURE;
00386        
00387        if (!aRegion || !mClipRegion)
00388               return NS_ERROR_NULL_POINTER;
00389        
00390        if (mClipRegion) {
00391               if (*aRegion) { // copy it, they should be using CopyClipRegion
00392                        (*aRegion)->SetTo(*mClipRegion);
00393                        rv = NS_OK;
00394                 } else {
00395                               nsCOMPtr<nsIRegion> newRegion = do_CreateInstance(kRegionCID, &rv);
00396                               if (NS_SUCCEEDED(rv)) {
00397                                      newRegion->Init();
00398                                      newRegion->SetTo(*mClipRegion);
00399                                      NS_ADDREF(*aRegion = newRegion);
00400                               }
00401                        }
00402        } else {
00403               rv = NS_ERROR_FAILURE;
00404        }
00405        return rv;
00406 }
00407 
00408 NS_IMETHODIMP nsRenderingContextPh :: SetFont( nsIFontMetrics *aFontMetrics ) 
00409 {
00410        if( mFontMetrics == aFontMetrics ) return NS_OK;
00411        
00412        nsFontHandle  fontHandle;                 /* really a nsString */
00413        char      *pFontHandle;
00414        
00415        NS_IF_RELEASE(mFontMetrics);
00416        mFontMetrics = aFontMetrics;
00417        NS_IF_ADDREF(mFontMetrics);
00418        
00419   if( mFontMetrics == nsnull ) return NS_OK;
00420        
00421        mFontMetrics->GetFontHandle( fontHandle );
00422        pFontHandle = (char *) fontHandle;
00423     
00424        if( pFontHandle ) {
00425               if( mPhotonFontName ) free( mPhotonFontName );
00426               mPhotonFontName = strdup( pFontHandle );
00427               }
00428        
00429        return NS_OK;
00430 }
00431 
00432 NS_IMETHODIMP nsRenderingContextPh :: CreateDrawingSurface( const nsRect &aBounds, PRUint32 aSurfFlags, nsIDrawingSurface* &aSurface ) 
00433 {
00434        if( mSurface ) {
00435               nsDrawingSurfacePh *surf = new nsDrawingSurfacePh();
00436               if( surf ) {
00437                      NS_ADDREF(surf);
00438                      /* we pass NULL as aGC here / it means use the default photon gc */
00439                      if( surf->Init( aBounds.width, aBounds.height, aSurfFlags ) == NS_OK ) {
00440                             aSurface = surf;
00441                             return NS_OK;
00442                             }
00443                      }
00444               }
00445        aSurface = nsnull;
00446        return NS_ERROR_FAILURE;
00447 }
00448 
00449 NS_IMETHODIMP nsRenderingContextPh :: DrawLine( nscoord aX0, nscoord aY0, nscoord aX1, nscoord aY1 ) 
00450 {
00451        nscoord diffX, diffY;
00452 
00453        mTranMatrix->TransformCoord( &aX0, &aY0 );
00454        mTranMatrix->TransformCoord( &aX1, &aY1 );
00455 
00456        diffX = aX1 - aX0;
00457        diffY = aY1 - aY0;
00458 
00459        if( diffX != 0 ) diffX = ( diffX > 0 ? 1 : -1 );
00460        if( diffY != 0 ) diffY = ( diffY > 0 ? 1 : -1 );
00461        
00462        UpdateGC();
00463        PgSetStrokeColorCx( mGC, mCurrentColor );
00464        PgSetStrokeDashCx( mGC, sLineStyle[mCurrentLineStyle], sLineStyleLen[mCurrentLineStyle], 0x10000 );
00465        
00466        PgDrawILineCx( mSurfaceDC, aX0, aY0, aX1-diffX, aY1-diffY );
00467        return NS_OK;
00468 }
00469 
00470 NS_IMETHODIMP nsRenderingContextPh :: DrawRect( nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight ) 
00471 {
00472        nscoord x,y,w,h;
00473        
00474        x = aX;
00475        y = aY;
00476        w = aWidth;
00477        h = aHeight;
00478        mTranMatrix->TransformCoord( &x, &y, &w, &h );
00479        
00480        UpdateGC();   
00481        PgSetStrokeColorCx( mGC, mCurrentColor );
00482        PgSetStrokeDashCx( mGC, sLineStyle[mCurrentLineStyle], sLineStyleLen[mCurrentLineStyle], 0x10000 );
00483 
00484        ConditionRect(x,y,w,h);     
00485        if( w && h )
00486               PgDrawIRectCx( mSurfaceDC, x, y, x + w - 1, y + h - 1, Pg_DRAW_STROKE );
00487        return NS_OK;
00488 }
00489 
00490 NS_IMETHODIMP nsRenderingContextPh :: FillRect( nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight ) 
00491 {
00492        nscoord x,y,w,h;
00493        
00494        x = aX;
00495        y = aY;
00496        w = aWidth;
00497        h = aHeight;
00498        
00499        mTranMatrix->TransformCoord( &x, &y, &w, &h );
00500 
00501        PgSetGC( NULL );
00502 /* ATENTIE */ PhDCSetCurrent( mSurfaceDC );
00503        
00504        UpdateGC();
00505        PgSetStrokeColorCx( mGC, mCurrentColor );
00506        PgSetStrokeDashCx( mGC, sLineStyle[mCurrentLineStyle], sLineStyleLen[mCurrentLineStyle], 0x10000 );
00507        PgSetFillColorCx( mGC, mCurrentColor );
00508 
00509        ConditionRect(x,y,w,h);     
00510        if( w && h ) {
00511               int y2 = y + h - 1;
00512               if( y < SHRT_MIN ) y = SHRT_MIN;                 /* on very large documents, the PgDrawIRect will take only the short part from the int, which could lead to randomly, hazardous results see PR: 5864 */
00513               if( y2 >= SHRT_MAX ) y2 = SHRT_MAX;              /* on very large documents, the PgDrawIRect will take only the short part from the int, which could lead to randomly, hazardous results see PR: 5864 */
00514               
00515               PgDrawIRectCx( mSurfaceDC, x, y, x + w - 1, y2, Pg_DRAW_FILL );
00516        }
00517        return NS_OK;
00518 }
00519 
00520 NS_IMETHODIMP nsRenderingContextPh :: InvertRect( nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight ) 
00521 {
00522        if( nsnull == mTranMatrix || nsnull == mSurface ) return NS_ERROR_FAILURE; 
00523        nscoord x,y,w,h;
00524        
00525        x = aX;
00526        y = aY;
00527        w = aWidth;
00528        h = aHeight;
00529        mTranMatrix->TransformCoord(&x,&y,&w,&h);
00530        
00531        if( !w || !h ) return NS_OK;
00532        
00533        UpdateGC();
00534        PgSetStrokeColorCx( mGC, mCurrentColor );
00535        PgSetStrokeDashCx( mGC, sLineStyle[mCurrentLineStyle], sLineStyleLen[mCurrentLineStyle], 0x10000 );
00536        PgSetFillColorCx( mGC, mCurrentColor );
00537 
00538        ConditionRect(x,y,w,h);
00539        PgSetFillColorCx( mGC, Pg_INVERT_COLOR );
00540        PgSetDrawModeCx( mGC, Pg_DRAWMODE_XOR );
00541        PgDrawIRectCx( mSurfaceDC, x, y, x + w - 1, y + h - 1, Pg_DRAW_FILL );
00542        PgSetDrawModeCx( mGC, Pg_DRAWMODE_OPAQUE );
00543 
00544        /* this is necessary here in 630 because of PR:18744 ( http://bugs.qnx.com ) - please remove it when the PR is fixed */
00545        PgFlushCx( mSurfaceDC );
00546 
00547        return NS_OK;
00548 }
00549 
00550 NS_IMETHODIMP nsRenderingContextPh :: DrawPolygon( const nsPoint aPoints[], PRInt32 aNumPoints ) 
00551 {
00552        PhPoint_t *pts;
00553        
00554        if( !aNumPoints ) return NS_OK;
00555        
00556        if( (pts = new PhPoint_t [aNumPoints]) != NULL ) {
00557               PhPoint_t pos = {0,0};
00558               PRInt32 i;
00559               int x,y;
00560               
00561               for( i = 0; i < aNumPoints; i++ ) {
00562                      x = aPoints[i].x;
00563                      y = aPoints[i].y;
00564                      mTranMatrix->TransformCoord(&x, &y);
00565                      pts[i].x = x;
00566                      pts[i].y = y;
00567               }
00568 
00569               UpdateGC();
00570               PgSetStrokeColorCx( mGC, mCurrentColor );
00571               PgSetStrokeDashCx( mGC, sLineStyle[mCurrentLineStyle], sLineStyleLen[mCurrentLineStyle], 0x10000 );
00572 
00573               if( aNumPoints == 4 ) {
00574                      /* this code makes the edges of the controls like buttons, texts etc appear less heavy */
00575                      int dx = pts[1].x - pts[0].x;
00576                      int dy = pts[1].y - pts[0].y;
00577                      if( !dx ) {
00578                             /* the edge is vertical - move us (0,1) closer to the other 2 points (2,3) */
00579                             pts[0].y++;
00580                             pts[1].y--;
00581                             int diff = pts[3].x > pts[0].x ? 1 : -1;
00582                             pts[0].x += diff;
00583                             pts[1].x += diff;
00584                             }
00585                      if( !dy ) {
00586                             /* the edge is horizontal - move the other 2 points (2,3) closer to us (0,1) */
00587                             pts[2].x++;
00588                             pts[3].x--;
00589                             int diff = pts[3].y > pts[0].y ? -1 : 1;
00590                             pts[2].y += diff;
00591                             pts[3].y += diff;
00592                             }
00593                      }
00594 
00595 
00596               PgDrawPolygonCx( mSurfaceDC, pts, aNumPoints, &pos, Pg_DRAW_STROKE );
00597               delete [] pts;
00598        }
00599        return NS_OK;
00600 }
00601 
00602 
00603 NS_IMETHODIMP nsRenderingContextPh :: FillPolygon( const nsPoint aPoints[], PRInt32 aNumPoints ) 
00604 {
00605        PhPoint_t *pts;
00606        
00607        if( !aNumPoints ) return NS_OK;
00608        
00609        if( (pts = new PhPoint_t [aNumPoints]) != NULL ) {
00610               PhPoint_t pos = {0,0};
00611               PRInt32 i;
00612               int x,y;
00613               
00614               for( i = 0; i < aNumPoints; i++ ) {
00615                      x = aPoints[i].x;
00616                      y = aPoints[i].y;
00617                      mTranMatrix->TransformCoord(&x, &y);
00618                      pts[i].x = x;
00619                      pts[i].y = y;
00620               }
00621 
00622               UpdateGC();
00623               PgSetStrokeColorCx( mGC, mCurrentColor );
00624               PgSetStrokeDashCx( mGC, sLineStyle[mCurrentLineStyle], sLineStyleLen[mCurrentLineStyle], 0x10000 );
00625               PgSetFillColorCx( mGC, mCurrentColor );
00626 
00627               if( aNumPoints == 4 ) {
00628                      /* this code makes the edges of the controls like buttons, texts etc appear less heavy */
00629                      int dx = pts[1].x - pts[0].x;
00630                      int dy = pts[1].y - pts[0].y;
00631                      if( !dx ) {
00632                             /* the edge is vertical - move us (0,1) closer to the other 2 points (2,3) */
00633                             pts[0].y++;
00634                             pts[1].y--;
00635                             int diff = pts[3].x > pts[0].x ? 1 : -1;
00636                             pts[0].x += diff;
00637                             pts[1].x += diff;
00638                             }
00639                      if( !dy ) {
00640                             /* the edge is horizontal - move the other 2 points (2,3) closer to us (0,1) */
00641                             pts[2].x++;
00642                             pts[3].x--;
00643                             int diff = pts[3].y > pts[0].y ? -1 : 1;
00644                             pts[2].y += diff;
00645                             pts[3].y += diff;
00646                             }
00647                      }
00648 
00649 
00650               PgDrawPolygonCx( mSurfaceDC, pts, aNumPoints, &pos, Pg_DRAW_FILL );
00651               delete [] pts;
00652        }
00653        return NS_OK;
00654 }
00655 
00656 NS_IMETHODIMP nsRenderingContextPh :: DrawEllipse( nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight ) 
00657 {
00658        nscoord x,y,w,h;
00659        PhPoint_t center;
00660        PhPoint_t radii;
00661        
00662        x = aX;
00663        y = aY;
00664        w = aWidth;
00665        h = aHeight;
00666        mTranMatrix->TransformCoord( &x, &y, &w, &h );
00667        
00668        center.x = x;
00669        center.y = y;
00670        radii.x = x+w-1;
00671        radii.y = y+h-1;
00672 
00673        UpdateGC();
00674        PgSetStrokeColorCx( mGC, mCurrentColor );
00675        PgSetStrokeDashCx( mGC, sLineStyle[mCurrentLineStyle], sLineStyleLen[mCurrentLineStyle], 0x10000 );
00676 
00677        PgDrawEllipseCx( mSurfaceDC, &center, &radii, Pg_EXTENT_BASED | Pg_DRAW_STROKE );
00678        return NS_OK;
00679 }
00680 
00681 NS_IMETHODIMP nsRenderingContextPh :: FillEllipse( nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight ) 
00682 {
00683        nscoord x,y,w,h;
00684        PhPoint_t center;
00685        PhPoint_t radii;
00686        
00687        x = aX;
00688        y = aY;
00689        w = aWidth;
00690        h = aHeight;
00691        mTranMatrix->TransformCoord(&x,&y,&w,&h);
00692        
00693        center.x = x;
00694        center.y = y;
00695        radii.x = x+w-1;
00696        radii.y = y+h-1;
00697        
00698        UpdateGC();
00699        PgSetStrokeColorCx( mGC, mCurrentColor );
00700        PgSetStrokeDashCx( mGC, sLineStyle[mCurrentLineStyle], sLineStyleLen[mCurrentLineStyle], 0x10000 );
00701        PgSetFillColorCx( mGC, mCurrentColor );
00702 
00703        PgDrawEllipseCx( mSurfaceDC, &center, &radii, Pg_EXTENT_BASED | Pg_DRAW_FILL );
00704        return NS_OK;
00705 }
00706 
00707 NS_IMETHODIMP nsRenderingContextPh :: DrawArc(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight, float aStartAngle, float aEndAngle ) 
00708 {
00709        nscoord x,y,w,h;
00710        PhPoint_t center;
00711        PhPoint_t radii;
00712        
00713        x = aX;
00714        y = aY;
00715        w = aWidth;
00716        h = aHeight;
00717        
00718        mTranMatrix->TransformCoord(&x,&y,&w,&h);
00719        
00720        center.x = x;
00721        center.y = y;
00722        radii.x = x+w-1;
00723        radii.y = y+h-1;
00724        
00725        UpdateGC();
00726        PgSetStrokeColorCx( mGC, mCurrentColor );
00727        PgSetStrokeDashCx( mGC, sLineStyle[mCurrentLineStyle], sLineStyleLen[mCurrentLineStyle], 0x10000 );
00728 
00729        PgDrawArcCx( mSurfaceDC, &center, &radii, (unsigned int)aStartAngle, (unsigned int)aEndAngle, Pg_EXTENT_BASED | Pg_DRAW_STROKE );
00730        return NS_OK;
00731 }
00732 
00733 NS_IMETHODIMP nsRenderingContextPh :: FillArc( nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight, float aStartAngle, float aEndAngle ) 
00734 {
00735        nscoord x,y,w,h;
00736        PhPoint_t center;
00737        PhPoint_t radii;
00738        
00739        x = aX;
00740        y = aY;
00741        w = aWidth;
00742        h = aHeight;
00743        mTranMatrix->TransformCoord(&x,&y,&w,&h);
00744        
00745        center.x = x;
00746        center.y = y;
00747        radii.x = x+w-1;
00748        radii.y = y+h-1;
00749        
00750        UpdateGC();
00751        PgSetStrokeColorCx( mGC, mCurrentColor );
00752        PgSetStrokeDashCx( mGC, sLineStyle[mCurrentLineStyle], sLineStyleLen[mCurrentLineStyle], 0x10000 );
00753        PgSetFillColorCx( mGC, mCurrentColor );
00754 
00755        PgDrawArcCx( mSurfaceDC, &center, &radii, (unsigned int)aStartAngle, (unsigned int)aEndAngle, Pg_EXTENT_BASED | Pg_DRAW_FILL );
00756        return NS_OK;
00757 }
00758 
00759 
00760 NS_IMETHODIMP nsRenderingContextPh :: GetWidth(const char* aString, PRUint32 aLength, nscoord& aWidth ) 
00761 {
00762        PhRect_t extent;
00763 
00764        /* Check for the very common case of trying to get the width of a single space */
00765        if( aString[0] == ' ' && aLength == 1 )
00766               return mFontMetrics->GetSpaceWidth(aWidth);
00767 
00768        PfExtent( &extent, NULL, mPhotonFontName, 0L, 0L, aString, aLength, PF_SIMPLE_METRICS, NULL );
00769        aWidth = NSToCoordRound((int) ((extent.lr.x - extent.ul.x + 1) * mP2T));
00770        return NS_OK;
00771 }
00772 
00773 NS_IMETHODIMP nsRenderingContextPh :: GetWidth( const PRUnichar *aString, PRUint32 aLength, nscoord &aWidth, PRInt32 *aFontID ) 
00774 {
00775        NS_ConvertUCS2toUTF8    theUnicodeString (aString, aLength);
00776        const char *s = theUnicodeString.get();
00777        return GetWidth( s, strlen(s), aWidth );
00778 }
00779 
00780 NS_IMETHODIMP nsRenderingContextPh::GetTextDimensions(const PRUnichar* aString, PRUint32 aLength,
00781                                                                                              nsTextDimensions& aDimensions, PRInt32* aFontID)
00782 {
00783        mFontMetrics->GetMaxAscent(aDimensions.ascent);
00784        mFontMetrics->GetMaxDescent(aDimensions.descent);
00785               
00786        NS_ConvertUCS2toUTF8    theUnicodeString (aString, aLength);
00787        const char *s = theUnicodeString.get();
00788        return GetWidth( s, strlen(s), aDimensions.width );
00789 }
00790 
00791 NS_IMETHODIMP nsRenderingContextPh::DrawString(const char *aString, PRUint32 aLength,
00792                                                                                     nscoord aX, nscoord aY,
00793                                                                                     const nscoord* aSpacing)
00794 {
00795        if ( aLength == 0 )
00796               return NS_OK;
00797 
00798        UpdateGC();
00799        PgSetTextColorCx( mGC, mCurrentColor );
00800        
00801        PgSetFontCx( mGC, mPhotonFontName );
00802        PgSetExtendedTextFlagsCx( mGC, Pg_TEXT_SIMPLE_METRICS );
00803 
00804        if( !aSpacing ) {
00805               mTranMatrix->TransformCoord( &aX, &aY );
00806               PhPoint_t pos = { aX, aY };
00807               PgDrawTextCharsCx( mSurfaceDC, aString, aLength, &pos, Pg_TEXT_LEFT);
00808               }
00809        else {
00810     nscoord x = aX;
00811     nscoord y = aY;
00812     const char* end = aString + aLength;
00813     while( aString < end ) {
00814                      const char *ch = aString;
00815                      int charlen = utf8len( aString, aLength );
00816                      if( charlen <= 0 )
00817                             break;
00818 
00819                      aString += charlen;
00820                      aLength -= charlen;
00821 
00822       nscoord xx = x;
00823       nscoord yy = y;
00824       mTranMatrix->TransformCoord(&xx, &yy);
00825       PhPoint_t pos = { xx, yy };
00826                      PgDrawTextCx( mSurfaceDC, ch, charlen, &pos, Pg_TEXT_LEFT);
00827                      x += *aSpacing++;
00828                      }
00829               }
00830 
00831        PgSetExtendedTextFlagsCx( mGC, 0 );
00832 
00833        return NS_OK;
00834 }
00835 
00836 NS_IMETHODIMP nsRenderingContextPh::DrawImage( nsIImage *aImage, const nsRect& aSRect, const nsRect& aDRect ) 
00837 {
00838        nsRect    sr,dr;
00839        
00840        sr = aSRect;
00841        mTranMatrix->TransformCoord(&sr.x, &sr.y, &sr.width, &sr.height);
00842        sr.x -= mTranMatrix->GetXTranslationCoord();
00843        sr.y -= mTranMatrix->GetYTranslationCoord();
00844        
00845        dr = aDRect;
00846        mTranMatrix->TransformCoord(&dr.x, &dr.y, &dr.width, &dr.height);
00847        
00848        return aImage->Draw(*this, mSurface,
00849                                           sr.x, sr.y,
00850                                           sr.width, sr.height,
00851                                           dr.x, dr.y,
00852                                           dr.width, dr.height);
00853 }
00854 
00859 NS_IMETHODIMP nsRenderingContextPh :: CopyOffScreenBits( nsIDrawingSurface* aSrcSurf, PRInt32 aSrcX, PRInt32 aSrcY, const nsRect &aDestBounds, PRUint32 aCopyFlags ) 
00860 {
00861        PhArea_t              darea, sarea;
00862        PRInt32               srcX = aSrcX;
00863        PRInt32               srcY = aSrcY;
00864        nsRect                drect = aDestBounds;
00865        nsDrawingSurfacePh    *destsurf;
00866 
00867        if( !aSrcSurf || !mTranMatrix || !mSurface ) return NS_ERROR_FAILURE;
00868        
00869        if( aCopyFlags & NS_COPYBITS_TO_BACK_BUFFER ) {
00870               NS_ASSERTION(!(nsnull == mSurface), "no back buffer");
00871               destsurf = mSurface;
00872        }
00873        else 
00874               destsurf = mOffscreenSurface;
00875        
00876        if( aCopyFlags & NS_COPYBITS_XFORM_SOURCE_VALUES )      
00877               mTranMatrix->TransformCoord( &srcX, &srcY );
00878        if( aCopyFlags & NS_COPYBITS_XFORM_DEST_VALUES )
00879               mTranMatrix->TransformCoord( &drect.x, &drect.y, &drect.width, &drect.height );
00880 
00881        mSurfaceDC = destsurf->Select();
00882        UpdateGC();
00883 
00884        sarea.pos.x = srcX;
00885        sarea.pos.y = srcY;
00886        sarea.size.w = drect.width;
00887        sarea.size.h = drect.height;
00888        darea.pos.x = drect.x;
00889        darea.pos.y = drect.y;
00890        darea.size.w = sarea.size.w;
00891        darea.size.h = sarea.size.h;
00892 
00893        PgContextBlitAreaCx( mSurfaceDC, ((nsDrawingSurfacePh *)aSrcSurf)->GetDC(), &sarea, mSurfaceDC, &darea );
00894        PgFlushCx( mSurfaceDC );
00895 
00896        return NS_OK;
00897 }
00898 
00899 #ifdef MOZ_MATHML
00900 
00903 NS_IMETHODIMP nsRenderingContextPh::GetBoundingMetrics(const char*        aString,
00904                                 PRUint32           aLength,
00905                                 nsBoundingMetrics& aBoundingMetrics)
00906 {
00907        return NS_ERROR_FAILURE;
00908 }
00909 
00913 NS_IMETHODIMP nsRenderingContextPh::GetBoundingMetrics(const PRUnichar*   aString,
00914                                 PRUint32           aLength,
00915                                 nsBoundingMetrics& aBoundingMetrics,
00916                                 PRInt32*           aFontID = nsnull)
00917 {
00918        return NS_ERROR_FAILURE;
00919 }
00920 
00921 #endif /* MOZ_MATHML */
00922 
00923 
00924 void nsRenderingContextPh::ApplyClipping( PhGC_t *gc ) 
00925 {
00926        
00927        if( mClipRegion ) {
00928               PhTile_t    *tiles = nsnull;
00929               PhRect_t    *rects = nsnull;
00930               int         rect_count;
00931               
00932               /* no offset needed use the normal tile list */
00933               mClipRegion->GetNativeRegion((void*&)tiles);
00934               
00935               if( tiles != nsnull ) {
00936                      rects = PhTilesToRects( tiles, &rect_count );
00937                      PgSetMultiClipCx( gc, rect_count, rects );
00938                      free( rects );
00939               }
00940               else PgSetMultiClipCx( gc, 0, NULL );
00941        }
00942 }