Back to index

lightning-sunbird  0.9+nobinonly
nsRenderingContextPS.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  *   Roland Mainz <roland.mainz@informatik.med.uni-giessen.de>
00024  *   Leon Sha <leon.sha@sun.com>
00025  *   Ken Herron <kherron@fastmail.us>
00026  *
00027  * Alternatively, the contents of this file may be used under the terms of
00028  * either of the GNU General Public License Version 2 or later (the "GPL"),
00029  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00030  * in which case the provisions of the GPL or the LGPL are applicable instead
00031  * of those above. If you wish to allow use of your version of this file only
00032  * under the terms of either the GPL or the LGPL, and not to allow others to
00033  * use your version of this file under the terms of the MPL, indicate your
00034  * decision by deleting the provisions above and replace them with the notice
00035  * and other provisions required by the GPL or the LGPL. If you do not delete
00036  * the provisions above, a recipient may use your version of this file under
00037  * the terms of any one of the MPL, the GPL or the LGPL.
00038  *
00039  * ***** END LICENSE BLOCK ***** */
00040 
00041 #include "nsRenderingContextPS.h"
00042 #include "nsFontMetricsPS.h"
00043 #include "nsDeviceContextPS.h"
00044 #include "nsPostScriptObj.h"  
00045 #include "nsIRegion.h"      
00046 #include "nsIImage.h"
00047 #include "imgIContainer.h"
00048 #include "gfxIImageFrame.h"
00049 #include "nsIInterfaceRequestor.h"
00050 #include "nsIInterfaceRequestorUtils.h"
00051 #include "nsEPSObjectPS.h"
00052 #include "nsLocalFile.h"
00053 
00054 #include <stdio.h>
00055 #include <math.h>
00056 
00057 #define NS_PIXELS_TO_POINTS(x) ((x) * 10)
00058 
00059 #define FLAG_CLIP_VALID       0x0001
00060 #define FLAG_CLIP_CHANGED     0x0002
00061 #define FLAG_LOCAL_CLIP_VALID 0x0004
00062 
00063 #define FLAGS_ALL             (FLAG_CLIP_VALID | FLAG_CLIP_CHANGED | FLAG_LOCAL_CLIP_VALID)
00064 
00070 class PS_State
00071 {
00072 public:
00073   PS_State();
00074   PS_State(PS_State &aState);
00075   ~PS_State();
00076 
00077   PS_State        *mNext;
00078   nsTransform2D   mMatrix;
00079   nsRect          mLocalClip;
00080   nsCOMPtr<nsIFontMetrics>  mFontMetrics;
00081   nscolor         mCurrentColor;
00082   nscolor         mTextColor;
00083   nsLineStyle     mLineStyle;
00084   PRInt32         mFlags;
00085 };
00086 
00091 PS_State :: PS_State()
00092 {
00093   mNext         = nsnull;
00094   mMatrix.SetToIdentity();  
00095   mLocalClip.x = mLocalClip.y = mLocalClip.width = mLocalClip.height = 0;
00096   mFontMetrics  = nsnull;
00097   mCurrentColor = NS_RGB(0, 0, 0);
00098   mTextColor    = NS_RGB(0, 0, 0);
00099   mLineStyle    = nsLineStyle_kSolid;
00100 }
00101 
00107 PS_State :: PS_State(PS_State &aState) : 
00108   mMatrix(&aState.mMatrix),
00109   mLocalClip(aState.mLocalClip)
00110 {
00111   mNext = &aState;
00112   //mClipRegion = nsnull;
00113   mCurrentColor = aState.mCurrentColor;
00114   mFontMetrics = nsnull;
00115   //mFont = nsnull;
00116   mFlags = ~FLAGS_ALL;
00117   mTextColor = aState.mTextColor;
00118   mLineStyle = aState.mLineStyle;
00119 }
00120 
00125 PS_State :: ~PS_State()
00126 {
00127   //if (nsnull != mClipRegion){
00128     //VERIFY(::DeleteObject(mClipRegion));
00129     //mClipRegion = nsnull;
00130   //}
00131 
00132   //don't delete this because it lives in the font metrics
00133   //mFont = nsnull;
00134 }
00135 
00136 
00137 NS_IMPL_ISUPPORTS1(nsRenderingContextPS, nsIRenderingContext)
00138 
00139 
00143 nsRenderingContextPS :: nsRenderingContextPS()
00144 {
00145   mPSObj = nsnull;     // local copy of printcontext, will be set on the init process
00146   mContext = nsnull;
00147   mFontMetrics = nsnull;
00148 
00149   mStateCache = new nsVoidArray();
00150 
00151   mP2T = 1.0f;
00152 
00153   PushState();
00154 }
00155 
00160 nsRenderingContextPS::~nsRenderingContextPS()
00161 {
00162   if (mStateCache){
00163     PRInt32 cnt = mStateCache->Count();
00164 
00165     while (--cnt >= 0){
00166       PS_State *state = (PS_State *)mStateCache->ElementAt(cnt);
00167       mStateCache->RemoveElementAt(cnt);
00168 
00169       if (state)
00170         delete state;
00171     }
00172 
00173     delete mStateCache;
00174     mStateCache = nsnull;
00175   }
00176 
00177   mTranMatrix = nsnull;
00178 }
00179 
00184 NS_IMETHODIMP
00185 nsRenderingContextPS::Init(nsIDeviceContext* aContext)
00186 {
00187   NS_ENSURE_TRUE(nsnull != aContext, NS_ERROR_NULL_POINTER);
00188 
00189   mContext = aContext;
00190   mP2T = mContext->DevUnitsToAppUnits();
00191 
00192   mPSObj = NS_REINTERPRET_CAST(nsDeviceContextPS *, mContext.get())->GetPrintContext();
00193 
00194   NS_ENSURE_TRUE(nsnull != mPSObj, NS_ERROR_NULL_POINTER);
00195 
00196   // Layout's coordinate system places the origin at top left with Y
00197   // increasing down; PS places the origin at bottom left with Y increasing
00198   // upward. Both systems use twips for units, so no resizing is needed.
00199   mTranMatrix->SetToScale(1.0, -1.0);
00200   mTranMatrix->AddTranslation(0, -mPSObj->mPrintSetup->height);
00201 
00202   return NS_OK;
00203 }
00204 
00209 NS_IMETHODIMP nsRenderingContextPS :: LockDrawingSurface(PRInt32 aX, PRInt32 aY,
00210                                                           PRUint32 aWidth, PRUint32 aHeight,
00211                                                           void **aBits, PRInt32 *aStride,
00212                                                           PRInt32 *aWidthBytes, PRUint32 aFlags)
00213 {
00214   return NS_OK;
00215 }
00216 
00221 NS_IMETHODIMP nsRenderingContextPS :: UnlockDrawingSurface(void)
00222 {
00223   return NS_OK;
00224 }
00225 
00230 NS_IMETHODIMP
00231 nsRenderingContextPS :: SelectOffScreenDrawingSurface(nsIDrawingSurface* aSurface)
00232 {
00233   return NS_OK;
00234 }
00235 
00240 NS_IMETHODIMP
00241 nsRenderingContextPS :: GetDrawingSurface(nsIDrawingSurface* *aSurface)
00242 {
00243   *aSurface = nsnull;
00244   return NS_OK;
00245 }
00246 
00251 NS_IMETHODIMP
00252 nsRenderingContextPS :: GetHints(PRUint32& aResult)
00253 {
00254   return NS_OK;
00255 }
00256 
00261 NS_IMETHODIMP 
00262 nsRenderingContextPS :: Reset()
00263 {
00264   return NS_OK;
00265 }
00266 
00271 NS_IMETHODIMP 
00272 nsRenderingContextPS :: GetDeviceContext(nsIDeviceContext *&aContext)
00273 {
00274   aContext = mContext;
00275   NS_IF_ADDREF(aContext);
00276   return NS_OK;
00277 }
00278 
00279 
00284 NS_IMETHODIMP 
00285 nsRenderingContextPS :: PushState(void)
00286 {
00287   PRInt32 cnt = mStateCache->Count();
00288 
00289   if (cnt == 0){
00290     if (nsnull == mStates)
00291       mStates = new PS_State();
00292     else
00293       mStates = new PS_State(*mStates);
00294   } else {
00295     PS_State *state = (PS_State *)mStateCache->ElementAt(cnt - 1);
00296     mStateCache->RemoveElementAt(cnt - 1);
00297 
00298     state->mNext = mStates;
00299 
00300     //clone state info
00301     state->mMatrix = mStates->mMatrix;
00302     state->mLocalClip = mStates->mLocalClip;
00303     state->mCurrentColor = mStates->mCurrentColor;
00304     state->mFontMetrics = mStates->mFontMetrics;
00305     state->mTextColor = mStates->mTextColor;
00306     state->mLineStyle = mStates->mLineStyle;
00307 
00308     mStates = state;
00309   }
00310 
00311   mTranMatrix = &mStates->mMatrix;
00312 
00313   // at startup, the graphics state is not saved yet
00314   if(mPSObj)
00315     mPSObj->graphics_save();
00316 
00317   return NS_OK;
00318 }
00319 
00324 NS_IMETHODIMP 
00325 nsRenderingContextPS :: PopState(void)
00326 {
00327   if (nsnull == mStates){
00328     NS_ASSERTION(!(nsnull == mStates), "state underflow");
00329   } else {
00330     PS_State *oldstate = mStates;
00331 
00332     mStates = mStates->mNext;
00333 
00334     mStateCache->AppendElement(oldstate);
00335 
00336     if (nsnull != mStates){
00337       mTranMatrix = &mStates->mMatrix;
00338       SetLineStyle(mStates->mLineStyle);
00339     }
00340     else
00341       mTranMatrix = nsnull;
00342   }
00343 
00344   mPSObj->graphics_restore();
00345 
00346   return NS_OK;
00347 }
00348 
00353 NS_IMETHODIMP nsRenderingContextPS :: IsVisibleRect(const nsRect& aRect, PRBool &aVisible)
00354 {
00355   aVisible = PR_TRUE;
00356   return NS_OK;
00357 }
00358 
00363 NS_IMETHODIMP nsRenderingContextPS :: SetClipRect(const nsRect& aRect, nsClipCombine aCombine)
00364 {
00365   nsRect  trect = aRect;
00366 
00367   mStates->mLocalClip = aRect;
00368 
00369   mTranMatrix->TransformCoord(&trect.x, &trect.y,&trect.width, &trect.height);
00370   mStates->mFlags |= FLAG_LOCAL_CLIP_VALID;
00371 
00372   if (aCombine == nsClipCombine_kIntersect){
00373     mPSObj->newpath();
00374     mPSObj->box(trect.x, trect.y, trect.width, trect.height);
00375   } else if (aCombine == nsClipCombine_kUnion){
00376     mPSObj->newpath();
00377     mPSObj->box(trect.x, trect.y, trect.width, trect.height);
00378   }else if (aCombine == nsClipCombine_kSubtract){
00379     mPSObj->newpath();
00380     mPSObj->clippath();   // get the current path
00381     mPSObj->box_subtract(trect.x, trect.y, trect.width, trect.height);
00382   }else if (aCombine == nsClipCombine_kReplace){
00383     mPSObj->initclip();
00384     mPSObj->newpath();
00385     mPSObj->box(trect.x, trect.y, trect.width, trect.height);
00386   }else{
00387     NS_ASSERTION(PR_FALSE, "illegal clip combination");
00388     return NS_ERROR_INVALID_ARG;
00389   }
00390   mPSObj->clip();
00391   mPSObj->newpath();
00392 
00393   return NS_OK;
00394 }
00395 
00400 NS_IMETHODIMP 
00401 nsRenderingContextPS :: GetClipRect(nsRect &aRect, PRBool &aClipValid)
00402 {
00403   if (mStates->mLocalClip.width !=0){
00404     aRect = mStates->mLocalClip;
00405     aClipValid = PR_TRUE;
00406   }else{
00407     aClipValid = PR_FALSE;
00408   }
00409 
00410   return NS_OK;
00411 }
00412 
00417 NS_IMETHODIMP 
00418 nsRenderingContextPS :: SetClipRegion(const nsIRegion& aRegion, nsClipCombine aCombine)
00419 {
00420   nsRect rect;
00421   nsIRegion* pRegion = (nsIRegion*)&aRegion;
00422   pRegion->GetBoundingBox(&rect.x, &rect.y, &rect.width, &rect.height);
00423   SetClipRect(rect, aCombine);
00424 
00425   return NS_OK; 
00426 }
00427 
00432 NS_IMETHODIMP 
00433 nsRenderingContextPS :: CopyClipRegion(nsIRegion &aRegion)
00434 {
00435   //XXX wow, needs to do something.
00436   return NS_OK; 
00437 }
00438 
00443 NS_IMETHODIMP 
00444 nsRenderingContextPS :: GetClipRegion(nsIRegion **aRegion)
00445 {
00446   //XXX wow, needs to do something.
00447   return NS_OK; 
00448 }
00449 
00454 NS_IMETHODIMP 
00455 nsRenderingContextPS :: SetColor(nscolor aColor)
00456 {
00457   mPSObj->setcolor(aColor);
00458   mCurrentColor = aColor;
00459 
00460   return NS_OK;
00461 }
00462 
00467 NS_IMETHODIMP nsRenderingContextPS :: GetColor(nscolor &aColor) const
00468 {
00469   aColor = mCurrentColor;
00470   return NS_OK;
00471 }
00472 
00477 NS_IMETHODIMP nsRenderingContextPS :: SetLineStyle(nsLineStyle aLineStyle)
00478 {
00479   mCurrLineStyle = aLineStyle;
00480   return NS_OK;
00481 }
00482 
00487 NS_IMETHODIMP 
00488 nsRenderingContextPS :: GetLineStyle(nsLineStyle &aLineStyle)
00489 {
00490   aLineStyle = mCurrLineStyle;
00491   return NS_OK;
00492 }
00493 
00498 NS_IMETHODIMP 
00499 nsRenderingContextPS::SetFont(const nsFont& aFont, nsIAtom* aLangGroup)
00500 {
00501   nsCOMPtr<nsIFontMetrics> newMetrics;
00502   nsresult rv = mContext->GetMetricsFor( aFont, aLangGroup, *getter_AddRefs(newMetrics) );
00503 
00504   if (NS_SUCCEEDED(rv)) {
00505     rv = SetFont(newMetrics);
00506   }
00507   return rv;
00508 }
00509 
00514 NS_IMETHODIMP 
00515 nsRenderingContextPS::SetFont(nsIFontMetrics *aFontMetrics)
00516 {
00517   mFontMetrics = (nsFontMetricsPS *)aFontMetrics;
00518   return NS_OK;
00519 }
00520 
00525 NS_IMETHODIMP 
00526 nsRenderingContextPS::GetFontMetrics(nsIFontMetrics *&aFontMetrics)
00527 {
00528   aFontMetrics = (nsIFontMetrics *)mFontMetrics;
00529   NS_IF_ADDREF(aFontMetrics);
00530   return NS_OK;
00531 }
00532 
00537 NS_IMETHODIMP 
00538 nsRenderingContextPS::Translate(nscoord aX, nscoord aY)
00539 {
00540   mTranMatrix->AddTranslation((float)aX,(float)aY);
00541   return NS_OK;
00542 }
00543 
00548 NS_IMETHODIMP 
00549 nsRenderingContextPS :: Scale(float aSx, float aSy)
00550 {
00551        mTranMatrix->AddScale(aSx, aSy);
00552   return NS_OK;
00553 }
00554 
00559 NS_IMETHODIMP 
00560 nsRenderingContextPS :: GetCurrentTransform(nsTransform2D *&aTransform)
00561 {
00562   aTransform = mTranMatrix;
00563   return NS_OK;
00564 }
00565 
00570 NS_IMETHODIMP 
00571 nsRenderingContextPS :: CreateDrawingSurface(const nsRect& aBounds, PRUint32 aSurfFlags, nsIDrawingSurface* &aSurface)
00572 {
00573   return NS_OK;   // offscreen test
00574 }
00575 
00580 NS_IMETHODIMP 
00581 nsRenderingContextPS :: DestroyDrawingSurface(nsIDrawingSurface* aDS)
00582 {
00583   return NS_OK;   // offscreen test
00584 }
00585 
00590 NS_IMETHODIMP 
00591 nsRenderingContextPS :: DrawLine(nscoord aX0, nscoord aY0, nscoord aX1, nscoord aY1)
00592 {
00593   if (nsLineStyle_kNone == mCurrLineStyle)
00594     return NS_OK;
00595 
00596   // Layout expects lines to be one scaled pixel wide.
00597   float scale;
00598   NS_REINTERPRET_CAST(DeviceContextImpl *, mContext.get())->GetCanonicalPixelScale(scale);
00599   int width = NSToCoordRound(TWIPS_PER_POINT_FLOAT * scale);
00600 
00601   // If this line is vertical (horizontal), the geometric line defined
00602   // by our start and end points is actually the left edge (top edge)
00603   // of the line that should appear on the page.
00604   if (aX0 == aX1) {
00605     // Vertical. For better control we draw this as a filled
00606     // rectangle instead of a stroked line.
00607     return FillRect(aX0, aY0, width, aY1 - aY0);
00608   }
00609   else if (aY0 == aY1) {
00610     // Horizontal.
00611     return FillRect(aX0, aY0, aX1 - aX0, width);
00612   }
00613   else {
00614     // Angled line. Just stroke it.
00615     mTranMatrix->TransformCoord(&aX0,&aY0);
00616     mTranMatrix->TransformCoord(&aX1,&aY1);
00617     mPSObj->line(aX0, aY0, aX1, aY1, width);
00618     return NS_OK;
00619   }
00620 }
00621 
00626 NS_IMETHODIMP 
00627 nsRenderingContextPS :: DrawPolyline(const nsPoint aPoints[], PRInt32 aNumPoints)
00628 {
00629 
00630 const nsPoint*  np;
00631 nsPoint         pp;
00632 
00633   // First transform nsPoint's into POINT's; perform coordinate space
00634   // transformation at the same time
00635   np = &aPoints[0];
00636 
00637   pp.x = np->x;
00638   pp.y = np->y;
00639   mTranMatrix->TransformCoord(&pp.x, &pp.y);
00640   mPSObj->moveto(pp.x, pp.y);
00641   np++;
00642 
00643   // we are ignoring the linestyle
00644        for (PRInt32 i = 1; i < aNumPoints; i++, np++){
00645               pp.x = np->x;
00646               pp.y = np->y;
00647                 mTranMatrix->TransformCoord(&pp.x, &pp.y);
00648                 mPSObj->lineto(pp.x, pp.y);
00649        }
00650 
00651   // we dont close the path, this will give us a polyline
00652   mPSObj->stroke();
00653 
00654   return NS_OK;
00655 }
00656 
00661 NS_IMETHODIMP 
00662 nsRenderingContextPS :: DrawRect(const nsRect& aRect)
00663 {
00664   return DrawRect(aRect.x, aRect.y, aRect.width, aRect.height);
00665 }
00666 
00671 NS_IMETHODIMP 
00672 nsRenderingContextPS :: DrawRect(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight)
00673 {
00674 
00675        mTranMatrix->TransformCoord(&aX,&aY,&aWidth,&aHeight);
00676   mPSObj->newpath();
00677   mPSObj->box(aX, aY, aWidth, aHeight);
00678   mPSObj->stroke();
00679   return NS_OK;
00680 }
00681 
00686 NS_IMETHODIMP 
00687 nsRenderingContextPS :: FillRect(const nsRect& aRect)
00688 {
00689   return FillRect(aRect.x, aRect.y, aRect.width, aRect.height);
00690 }
00691 
00696 NS_IMETHODIMP 
00697 nsRenderingContextPS :: FillRect(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight)
00698 {
00699 
00700        mTranMatrix->TransformCoord(&aX,&aY,&aWidth,&aHeight);
00701   mPSObj->newpath();
00702   mPSObj->box(aX, aY, aWidth, aHeight);
00703   mPSObj->fill();
00704   return NS_OK;
00705 }
00706 
00707 NS_IMETHODIMP 
00708 nsRenderingContextPS :: InvertRect(const nsRect& aRect)
00709 {
00710        NS_NOTYETIMPLEMENTED("nsRenderingContextPS::InvertRect");
00711 
00712   return NS_OK;
00713 }
00714 
00715 NS_IMETHODIMP 
00716 nsRenderingContextPS :: InvertRect(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight)
00717 {
00718        NS_NOTYETIMPLEMENTED("nsRenderingContextPS::InvertRect");
00719 
00720   return NS_OK;
00721 }
00722 
00727 NS_IMETHODIMP 
00728 nsRenderingContextPS :: DrawPolygon(const nsPoint aPoints[], PRInt32 aNumPoints)
00729 {
00730 const nsPoint*  np;
00731 nsPoint         pp;
00732 
00733   mPSObj->newpath();
00734 
00735   // point np to the polypoints
00736   np = &aPoints[0];
00737 
00738   // do the initial moveto
00739        pp.x = np->x;
00740        pp.y = np->y;
00741   mTranMatrix->TransformCoord(&pp.x, &pp.y);
00742   mPSObj->moveto(pp.x, pp.y);
00743   np++;
00744 
00745   // add all the points to the path
00746        for (PRInt32 i = 1; i < aNumPoints; i++, np++){
00747               pp.x = np->x;
00748               pp.y = np->y;
00749                 mTranMatrix->TransformCoord(&pp.x, &pp.y);
00750                 mPSObj->lineto(pp.x, pp.y);
00751        }
00752 
00753   mPSObj->closepath();
00754   mPSObj->stroke();
00755 
00756   return NS_OK;
00757 }
00758 
00763 NS_IMETHODIMP 
00764 nsRenderingContextPS :: FillPolygon(const nsPoint aPoints[], PRInt32 aNumPoints)
00765 {
00766 const nsPoint*  np;
00767 nsPoint         pp;
00768 
00769   mPSObj->newpath();
00770 
00771   // point np to the polypoints
00772   np = &aPoints[0];
00773 
00774   // do the initial moveto
00775        pp.x = np->x;
00776        pp.y = np->y;
00777   mTranMatrix->TransformCoord(&pp.x, &pp.y);
00778   mPSObj->moveto(pp.x, pp.y);
00779   np++;
00780 
00781   // add all the points to the path
00782        for (PRInt32 i = 1; i < aNumPoints; i++, np++){
00783               pp.x = np->x;
00784               pp.y = np->y;
00785                 mTranMatrix->TransformCoord(&pp.x, &pp.y);
00786                 mPSObj->lineto(pp.x, pp.y);
00787        }
00788 
00789   mPSObj->closepath();
00790   mPSObj->fill();
00791 
00792   return NS_OK;
00793 }
00794 
00799 NS_IMETHODIMP 
00800 nsRenderingContextPS :: DrawEllipse(const nsRect& aRect)
00801 {
00802   return DrawEllipse(aRect.x, aRect.y, aRect.width, aRect.height);
00803 }
00804 
00809 NS_IMETHODIMP 
00810 nsRenderingContextPS :: DrawEllipse(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight)
00811 {
00812   if (nsLineStyle_kNone == mCurrLineStyle)
00813     return NS_OK;
00814 
00815   //SetupPen();
00816   mTranMatrix->TransformCoord(&aX, &aY, &aWidth, &aHeight);
00817 
00818   mPSObj->comment("ellipse");
00819   mPSObj->newpath();
00820   mPSObj->moveto(aX, aY);
00821   mPSObj->arc(aWidth, aHeight, 0.0, 360.0);
00822   mPSObj->closepath();
00823   mPSObj->stroke();
00824 
00825   return NS_OK;
00826 }
00827 
00828 NS_IMETHODIMP 
00829 nsRenderingContextPS :: FillEllipse(const nsRect& aRect)
00830 {
00831   return FillEllipse(aRect.x, aRect.y, aRect.width, aRect.height);
00832 }
00833 
00838 NS_IMETHODIMP nsRenderingContextPS :: FillEllipse(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight)
00839 {
00840   mTranMatrix->TransformCoord(&aX, &aY, &aWidth, &aHeight);
00841 
00842   mPSObj->comment("ellipse");
00843   mPSObj->newpath();
00844   mPSObj->moveto(aX, aY);
00845   mPSObj->arc(aWidth, aHeight, 0.0, 360.0);
00846   mPSObj->closepath();
00847   mPSObj->fill();
00848 
00849   return NS_OK;
00850 }
00851 
00856 NS_IMETHODIMP 
00857 nsRenderingContextPS :: DrawArc(const nsRect& aRect,
00858                                  float aStartAngle, float aEndAngle)
00859 {
00860   return DrawArc(aRect.x,aRect.y,aRect.width,aRect.height,aStartAngle,aEndAngle);
00861 }
00862 
00867 NS_IMETHODIMP 
00868 nsRenderingContextPS :: DrawArc(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight,
00869                                  float aStartAngle, float aEndAngle)
00870 {
00871   if (nsLineStyle_kNone == mCurrLineStyle)
00872     return NS_OK;
00873 
00874   //SetupPen();
00875   mTranMatrix->TransformCoord(&aX, &aY, &aWidth, &aHeight);
00876 
00877   mPSObj->comment("arc");
00878   mPSObj->newpath();
00879   mPSObj->moveto(aX, aY);
00880   mPSObj->arc(aWidth, aHeight, aStartAngle, aEndAngle);
00881   mPSObj->closepath();
00882   mPSObj->stroke();
00883 
00884   return NS_OK;
00885 }
00886 
00891 NS_IMETHODIMP 
00892 nsRenderingContextPS :: FillArc(const nsRect& aRect,
00893                                  float aStartAngle, float aEndAngle)
00894 {
00895   return FillArc(aRect.x, aRect.y, aRect.width, aRect.height, aStartAngle, aEndAngle);
00896 }
00897 
00902 NS_IMETHODIMP 
00903 nsRenderingContextPS :: FillArc(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight,
00904                                  float aStartAngle, float aEndAngle)
00905 {
00906   if (nsLineStyle_kNone == mCurrLineStyle)
00907     return NS_OK;
00908 
00909   //SetupPen();
00910   mTranMatrix->TransformCoord(&aX, &aY, &aWidth, &aHeight);
00911 
00912   mPSObj->comment("arc");
00913   mPSObj->newpath();
00914   mPSObj->moveto(aX, aY);
00915   mPSObj->arc(aWidth, aHeight, aStartAngle, aEndAngle);
00916   mPSObj->closepath();
00917   mPSObj->fill();
00918 
00919   return NS_OK;
00920 }
00921 
00926 NS_IMETHODIMP 
00927 nsRenderingContextPS :: GetWidth(char ch, nscoord& aWidth)
00928 {
00929   char buf[1];
00930   buf[0] = ch;
00931   return GetWidth(buf, 1, aWidth);
00932 }
00933 
00938 NS_IMETHODIMP 
00939 nsRenderingContextPS::GetWidth(PRUnichar ch, nscoord &aWidth, PRInt32 *aFontID)
00940 {
00941   PRUnichar buf[1];
00942   buf[0] = ch;
00943   return GetWidth(buf, 1, aWidth, aFontID);
00944 }
00945 
00950 NS_IMETHODIMP 
00951 nsRenderingContextPS::GetWidth(const char* aString, nscoord& aWidth)
00952 {
00953   return GetWidth(aString, strlen(aString),aWidth);
00954 }
00955 
00960 NS_IMETHODIMP 
00961 nsRenderingContextPS::GetWidth(const char* aString,PRUint32 aLength,nscoord& aWidth)
00962 {
00963   nsresult rv = NS_ERROR_FAILURE;
00964   if (mFontMetrics) {
00965     rv = NS_REINTERPRET_CAST(nsFontMetricsPS *, mFontMetrics.get())->GetStringWidth(aString,aWidth,aLength);
00966   }
00967   
00968   return rv;
00969 }
00970 
00975 NS_IMETHODIMP 
00976 nsRenderingContextPS::GetWidth(const nsString& aString, nscoord& aWidth, PRInt32 *aFontID)
00977 {
00978   return GetWidth(aString.get(), aString.Length(), aWidth, aFontID);
00979 }
00980 
00985 NS_IMETHODIMP 
00986 nsRenderingContextPS :: GetWidth(const PRUnichar *aString,PRUint32 aLength,nscoord &aWidth, PRInt32 *aFontID)
00987 {
00988   nsresult rv = NS_ERROR_FAILURE;
00989 
00990   if (mFontMetrics) {
00991     rv = NS_REINTERPRET_CAST(nsFontMetricsPS *, mFontMetrics.get())->GetStringWidth(aString, aWidth, aLength);
00992   }
00993 
00994   return rv;
00995 }
00996 
00998 NS_IMETHODIMP
00999 nsRenderingContextPS::GetTextDimensions(const char*       aString,
01000                                         PRInt32           aLength,
01001                                         PRInt32           aAvailWidth,
01002                                         PRInt32*          aBreaks,
01003                                         PRInt32           aNumBreaks,
01004                                         nsTextDimensions& aDimensions,
01005                                         PRInt32&          aNumCharsFit,
01006                                         nsTextDimensions& aLastWordDimensions,
01007                                         PRInt32*          aFontID)
01008 {
01009   NS_NOTYETIMPLEMENTED("nsRenderingContextPS::GetTextDimensions");
01010   return NS_ERROR_NOT_IMPLEMENTED;
01011 }
01012 
01013 NS_IMETHODIMP
01014 nsRenderingContextPS::GetTextDimensions(const PRUnichar*  aString,
01015                                         PRInt32           aLength,
01016                                         PRInt32           aAvailWidth,
01017                                         PRInt32*          aBreaks,
01018                                         PRInt32           aNumBreaks,
01019                                         nsTextDimensions& aDimensions,
01020                                         PRInt32&          aNumCharsFit,
01021                                         nsTextDimensions& aLastWordDimensions,
01022                                         PRInt32*          aFontID)
01023 {
01024   NS_NOTYETIMPLEMENTED("nsRenderingContextPS::GetTextDimensions");
01025   return NS_ERROR_NOT_IMPLEMENTED;
01026 }
01027 
01028 NS_IMETHODIMP
01029 nsRenderingContextPS :: GetTextDimensions(const char* aString, PRUint32 aLength,
01030                                           nsTextDimensions& aDimensions)
01031 {
01032   nsresult rv = NS_ERROR_FAILURE;
01033 
01034   if (mFontMetrics) {
01035     nsFontMetricsPS *metrics = NS_REINTERPRET_CAST(nsFontMetricsPS *, mFontMetrics.get());
01036     metrics->GetStringWidth(aString, aDimensions.width, aLength);
01037     metrics->GetMaxAscent(aDimensions.ascent);
01038     metrics->GetMaxDescent(aDimensions.descent);
01039     rv = NS_OK;
01040   }
01041   
01042   return rv;
01043 }
01044 
01045 NS_IMETHODIMP
01046 nsRenderingContextPS :: GetTextDimensions(const PRUnichar* aString, PRUint32 aLength,
01047                                           nsTextDimensions& aDimensions, PRInt32* aFontID)
01048 {
01049   nsresult rv = NS_ERROR_FAILURE;
01050 
01051   if (mFontMetrics) {
01052     nsFontMetricsPS *metrics = NS_REINTERPRET_CAST(nsFontMetricsPS *, mFontMetrics.get());
01053     metrics->GetStringWidth(aString, aDimensions.width, aLength);
01054      //XXX temporary - bug 96609
01055     metrics->GetMaxAscent(aDimensions.ascent);
01056     metrics->GetMaxDescent(aDimensions.descent);
01057     rv = NS_OK;
01058   }
01059 
01060   return rv;
01061 }
01062 
01067 NS_IMETHODIMP
01068 nsRenderingContextPS :: DrawString(const char *aString, PRUint32 aLength,
01069                         nscoord aX, nscoord aY,
01070                         const nscoord* aSpacing)
01071 {
01072   NS_ENSURE_TRUE(mTranMatrix && mPSObj && mFontMetrics, NS_ERROR_NULL_POINTER);
01073 
01074   nsFontMetricsPS *metrics = NS_REINTERPRET_CAST(nsFontMetricsPS *, mFontMetrics.get());
01075   NS_ENSURE_TRUE(metrics, NS_ERROR_FAILURE);
01076 
01077   // When FT2 printing is enabled, we don't need to set langgroup
01078 #if defined(MOZ_ENABLE_FREETYPE2) || defined(MOZ_ENABLE_XFT)
01079   if (!NS_REINTERPRET_CAST(nsDeviceContextPS *, mContext.get())->mFTPEnable) {
01080 #endif
01081     nsCOMPtr<nsIAtom> langGroup;
01082     mFontMetrics->GetLangGroup(getter_AddRefs(langGroup));
01083     mPSObj->setlanggroup(langGroup);
01084 #if defined(MOZ_ENABLE_FREETYPE2) || defined(MOZ_ENABLE_XFT)
01085   }
01086 #endif
01087 
01088   if (aLength == 0)
01089     return NS_OK;
01090   nsFontPS* fontPS = nsFontPS::FindFont(aString[0], metrics->Font(), metrics);
01091   NS_ENSURE_TRUE(fontPS, NS_ERROR_FAILURE);
01092   fontPS->SetupFont(this);
01093 
01094   PRUint32 i, start = 0;
01095   for (i=0; i<aLength; i++) {
01096     nsFontPS* fontThisChar;
01097     fontThisChar = nsFontPS::FindFont(aString[i], metrics->Font(), metrics);
01098     NS_ENSURE_TRUE(fontThisChar, NS_ERROR_FAILURE);
01099     if (fontThisChar != fontPS) {
01100       // draw text up to this point
01101       aX += DrawString(aString+start, i-start, aX, aY, fontPS, 
01102                        aSpacing?aSpacing+start:nsnull);
01103       start = i;
01104 
01105       // setup for following text
01106       fontPS = fontThisChar;
01107       fontPS->SetupFont(this);
01108     }
01109   }
01110 
01111   // draw the last part
01112   if (aLength-start)
01113     DrawString(aString+start, aLength-start, aX, aY, fontPS, 
01114                aSpacing?aSpacing+start:nsnull);
01115 
01116   return NS_OK;
01117 }
01118 
01123 NS_IMETHODIMP 
01124 nsRenderingContextPS :: DrawString(const PRUnichar *aString, PRUint32 aLength,
01125                                     nscoord aX, nscoord aY, PRInt32 aFontID,
01126                                     const nscoord* aSpacing)
01127 {
01128   NS_ENSURE_TRUE(mTranMatrix && mPSObj && mFontMetrics, NS_ERROR_NULL_POINTER);
01129   
01130   nsFontMetricsPS *metrics = NS_REINTERPRET_CAST(nsFontMetricsPS *, mFontMetrics.get());
01131   NS_ENSURE_TRUE(metrics, NS_ERROR_FAILURE);
01132 
01133 #if defined(MOZ_ENABLE_FREETYPE2) || defined(MOZ_ENABLE_XFT)
01134   // When FT2 printing is enabled, we don't need to set langgroup
01135   if (!NS_REINTERPRET_CAST(nsDeviceContextPS *, mContext.get())->mFTPEnable) {
01136 #endif
01137     nsCOMPtr<nsIAtom> langGroup = nsnull;
01138     mFontMetrics->GetLangGroup(getter_AddRefs(langGroup));
01139     mPSObj->setlanggroup(langGroup);
01140 #if defined(MOZ_ENABLE_FREETYPE2) || defined(MOZ_ENABLE_XFT)
01141   }
01142 #endif
01143 
01144   /* build up conversion table */
01145   mPSObj->preshow(aString, aLength);
01146 
01147   if (aLength == 0)
01148     return NS_OK;
01149   nsFontPS* fontPS = nsFontPS::FindFont(aString[0], metrics->Font(), metrics);
01150   NS_ENSURE_TRUE(fontPS, NS_ERROR_FAILURE);
01151   fontPS->SetupFont(this);
01152 
01153   PRUint32 i, start = 0;
01154   for (i=0; i<aLength; i++) {
01155     nsFontPS* fontThisChar;
01156     fontThisChar = nsFontPS::FindFont(aString[i], metrics->Font(), metrics);
01157     NS_ENSURE_TRUE(fontThisChar, NS_ERROR_FAILURE);
01158     if (fontThisChar != fontPS) {
01159       // draw text up to this point
01160       aX += DrawString(aString+start, i-start, aX, aY, fontPS, 
01161                        aSpacing?aSpacing+start:nsnull);
01162       start = i;
01163 
01164       // setup for following text
01165       fontPS = fontThisChar;
01166       fontPS->SetupFont(this);
01167     }
01168   }
01169 
01170   // draw the last part
01171   if (aLength-start)
01172     DrawString(aString+start, aLength-start, aX, aY, fontPS, 
01173                aSpacing?aSpacing+start:nsnull);
01174 
01175   return NS_OK;
01176 }
01177 
01178 PRInt32 
01179 nsRenderingContextPS::DrawString(const char *aString, PRUint32 aLength,
01180                                  nscoord &aX, nscoord &aY, nsFontPS* aFontPS,
01181                                  const nscoord* aSpacing)
01182 {
01183   nscoord width = 0;
01184   PRInt32 x = aX;
01185   PRInt32 y = aY;
01186 
01187   PRInt32 dxMem[500];
01188   PRInt32* dx0 = 0;
01189   if (aSpacing) {
01190     dx0 = dxMem;
01191     if (aLength > 500) {
01192       dx0 = new PRInt32[aLength];
01193       NS_ENSURE_TRUE(dx0, NS_ERROR_OUT_OF_MEMORY);
01194     }
01195     mTranMatrix->ScaleXCoords(aSpacing, aLength, dx0);
01196   }
01197 
01198   mTranMatrix->TransformCoord(&x, &y);
01199   width = aFontPS->DrawString(this, x, y, aString, aLength);
01200 
01201   if ((aSpacing) && (dx0 != dxMem)) {
01202     delete [] dx0;
01203   }
01204 
01205   return width;
01206 }
01207 
01208 
01209 PRInt32 
01210 nsRenderingContextPS::DrawString(const PRUnichar *aString, PRUint32 aLength,
01211                                  nscoord aX, nscoord aY, nsFontPS* aFontPS,
01212                                  const nscoord* aSpacing)
01213 {
01214   nscoord width = 0;
01215   PRInt32 x = aX;
01216   PRInt32 y = aY;
01217 
01218   if (aSpacing) {
01219     // Slow, but accurate rendering
01220     const PRUnichar* end = aString + aLength;
01221     while (aString < end){
01222       x = aX;
01223       y = aY;
01224       mTranMatrix->TransformCoord(&x, &y);
01225       aFontPS->DrawString(this, x, y, aString, 1);
01226       aX += *aSpacing++;
01227       aString++;
01228     }
01229     width = aX;
01230   } else {
01231     mTranMatrix->TransformCoord(&x, &y);
01232     width = aFontPS->DrawString(this, x, y, aString, aLength);
01233   }
01234 
01235   return width;
01236 }
01237 
01242 NS_IMETHODIMP 
01243 nsRenderingContextPS :: DrawString(const nsString& aString,nscoord aX, nscoord aY, PRInt32 aFontID,
01244                                     const nscoord* aSpacing)
01245 {
01246   return DrawString(aString.get(), aString.Length(), aX, aY, aFontID, aSpacing);
01247 }
01248 
01249 NS_IMETHODIMP
01250 nsRenderingContextPS::DrawImage(imgIContainer *aImage, const nsRect & aSrcRect, const nsRect & aDestRect)
01251 {
01252   // Transform the destination rectangle.
01253   nsRect dr = aDestRect;
01254   mTranMatrix->TransformCoord(&dr.x, &dr.y, &dr.width, &dr.height);
01255 
01256   // Transform the source rectangle. We don't use the matrix for this;
01257   // just convert the twips back into points.
01258   nsRect sr = aSrcRect;
01259   sr.x /= TWIPS_PER_POINT_INT;
01260   sr.y /= TWIPS_PER_POINT_INT;
01261   sr.width /= TWIPS_PER_POINT_INT;
01262   sr.height /= TWIPS_PER_POINT_INT;
01263 
01264   nsCOMPtr<gfxIImageFrame> iframe;
01265   aImage->GetCurrentFrame(getter_AddRefs(iframe));
01266   if (!iframe) return NS_ERROR_FAILURE;
01267 
01268   nsCOMPtr<nsIImage> img(do_GetInterface(iframe));
01269   if (!img) return NS_ERROR_FAILURE;
01270 
01271   nsRect ir;
01272   iframe->GetRect(ir);
01273   mPSObj->draw_image(img, sr, ir, dr);
01274   return NS_OK;
01275 }
01276 
01277 NS_IMETHODIMP
01278 nsRenderingContextPS::DrawTile(imgIContainer *aImage,
01279                                nscoord aXImageStart,
01280                                nscoord aYImageStart,
01281                                const nsRect *aTargetRect)
01282 {
01283   // Get image size 
01284   nscoord width, height;
01285   aImage->GetWidth(&width);
01286   aImage->GetHeight(&height);
01287   
01288   // Second para for nsPostscriptObj::draw_image
01289   nsRect imgRect;
01290   imgRect.x = 0;
01291   imgRect.y = 0;
01292   imgRect.width = width;
01293   imgRect.height = height;
01294   
01295   // Transform image's width-height into twips
01296   width = NSToCoordRound(width*mP2T);
01297   height = NSToCoordRound(height*mP2T);
01298 
01299   // Get current frame
01300   nsCOMPtr<gfxIImageFrame> iframe;
01301   aImage->GetCurrentFrame(getter_AddRefs(iframe));
01302   if (!iframe) return NS_ERROR_FAILURE;
01303 
01304   // Third para for nsPoscriptObj::draw_image 
01305   nsCOMPtr<nsIImage> img(do_GetInterface(iframe));
01306   if (!img) return NS_ERROR_FAILURE;
01307   nsRect ir;
01308   iframe->GetRect(ir);
01309    
01310   // Save states
01311   mPSObj->graphics_save();
01312 
01313   // Set clip region for tile 
01314   nsRect targetRect = (*aTargetRect);
01315   mTranMatrix->TransformCoord(&targetRect.x, &targetRect.y, 
01316                               &targetRect.width, &targetRect.height);
01317   mPSObj->box(targetRect.x,targetRect.y,targetRect.width,targetRect.height);
01318   mPSObj->clip();
01319 
01320   // Begin drawing tiles
01321   nsRect dstRect;
01322   for(PRInt32 y = aYImageStart; y < aTargetRect->y + aTargetRect->height; y += height)
01323     for(PRInt32 x = aXImageStart; x < aTargetRect->x + aTargetRect->width; x += width)
01324     {
01325       dstRect.x = x;
01326       dstRect.y = y;
01327       dstRect.width = width;
01328       dstRect.height = height;
01329       mTranMatrix->TransformCoord(&dstRect.x, &dstRect.y, &dstRect.width, &dstRect.height);
01330       mPSObj->draw_image(img, imgRect, ir, dstRect);
01331     }
01332 
01333   // Restore states
01334   mPSObj->graphics_restore();
01335 
01336   return NS_OK;
01337 }
01338 
01339 
01340 #ifdef MOZ_MATHML
01341 
01344 NS_IMETHODIMP 
01345 nsRenderingContextPS::GetBoundingMetrics(const char*        aString,
01346                                          PRUint32           aLength,
01347                                          nsBoundingMetrics& aBoundingMetrics)
01348 {
01349   // Fill me up 
01350   return NS_ERROR_NOT_IMPLEMENTED;
01351 }
01352 
01356 NS_IMETHODIMP 
01357 nsRenderingContextPS::GetBoundingMetrics(const PRUnichar*   aString,
01358                                          PRUint32           aLength,
01359                                          nsBoundingMetrics& aBoundingMetrics,
01360                                          PRInt32*           aFontID)
01361 {
01362   // Fill me up 
01363   return NS_ERROR_NOT_IMPLEMENTED;
01364 }
01365 #endif /* MOZ_MATHML */
01366 
01371 NS_IMETHODIMP nsRenderingContextPS :: CopyOffScreenBits(nsIDrawingSurface* aSrcSurf,
01372                                                          PRInt32 aSrcX, PRInt32 aSrcY,
01373                                                          const nsRect &aDestBounds,
01374                                                          PRUint32 aCopyFlags)
01375 {
01376   return NS_OK;
01377 }
01378 
01379 NS_IMETHODIMP nsRenderingContextPS::RetrieveCurrentNativeGraphicData(void** ngd)
01380 {
01381   return NS_OK;
01382 }
01383 
01392 NS_IMETHODIMP nsRenderingContextPS::RenderEPS(const nsRect& aRect, FILE *aDataFile)
01393 {
01394   nsresult    rv;
01395 
01396   /* EPSFs aren't supposed to have side effects, so if width or height is
01397    * zero, just return. */
01398   if ((aRect.width == 0) || (aRect.height == 0))
01399     return NS_OK;
01400 
01401   nsEPSObjectPS eps(aDataFile);
01402   if (NS_FAILED(eps.GetStatus())) {
01403     return NS_ERROR_INVALID_ARG;
01404   }
01405  
01406   nsRect trect = aRect;
01407   mTranMatrix->TransformCoord(&trect.x, &trect.y, &trect.width, &trect.height);
01408  
01409   rv = mPSObj->render_eps(trect, eps);
01410 
01411   return rv;
01412 }
01413 
01414 #ifdef NOTNOW
01415 HPEN nsRenderingContextPS :: SetupSolidPen(void)
01416 {
01417   return mCurrPen;
01418 }
01419 
01420 HPEN nsRenderingContextPS :: SetupDashedPen(void)
01421 {
01422   return mCurrPen;
01423 }
01424 
01425 HPEN nsRenderingContextPS :: SetupDottedPen(void)
01426 {
01427   return mCurrPen;
01428 }
01429 
01430 #endif /* NOTNOW */
01431