/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* ***** BEGIN LICENSE BLOCK ***** * Version: NPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Netscape Public License * Version 1.1 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * http://www.mozilla.org/NPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is mozilla.org code. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the NPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the NPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include "nsCOMPtr.h" #include "nsRenderingContextImpl.h" #include "nsIDeviceContext.h" #include "nsIImage.h" #include "nsTransform2D.h" #include const nsPoint *gPts; nsDrawingSurface nsRenderingContextImpl::gBackbuffer = nsnull; nsRect nsRenderingContextImpl::gBackbufferBounds = nsRect(0, 0, 0, 0); nsSize nsRenderingContextImpl::gLargestRequestedSize = nsSize(0, 0); // comparison routines for qsort PRInt32 PR_CALLBACK compare_ind(const void *u,const void *v){return gPts[(PRInt32)*((PRInt32*)u)].y <= gPts[(PRInt32)*((PRInt32*)v)].y ? -1 : 1;} PRInt32 PR_CALLBACK compare_active(const void *u,const void *v){return ((Edge*)u)->x <= ((Edge*)v)->x ? -1 : 1;} /** --------------------------------------------------- * See documentation in nsIRenderingContext.h * @update 3/16/00 dwc */ nsRenderingContextImpl :: nsRenderingContextImpl() : mTranMatrix(nsnull) , mLineStyle(nsLineStyle_kSolid) , mAct(0) , mActive(nsnull) , mPenMode(nsPenMode_kNone) { } /** --------------------------------------------------- * See documentation in nsIRenderingContext.h * @update 3/16/00 dwc */ nsRenderingContextImpl :: ~nsRenderingContextImpl() { } /** --------------------------------------------------- * See documentation in nsIRenderingContext.h * @update 3/29/00 dwc */ NS_IMETHODIMP nsRenderingContextImpl::DrawPath(nsPathPoint aPointArray[],PRInt32 aNumPts) { PRInt32 i; nsPathPoint pts[20]; nsPathPoint *pp0,*np=0,*pp; QBezierCurve thecurve; nsPathIter::eSegType curveType; // Transform the points first if (aNumPts > 20){ pp0 = new nsPathPoint[aNumPts]; } else { pp0 = &pts[0]; } pp = pp0; np = &aPointArray[0]; for ( i= 0; i < aNumPts; i++,np++,pp++){ pp->x = np->x; pp->y = np->y; pp->mIsOnCurve = np->mIsOnCurve; mTranMatrix->TransformCoord((int*)&pp->x,(int*)&pp->y); } nsPathIter thePathIter (pp0,aNumPts); while ( thePathIter.NextSeg(thecurve,curveType) ) { // draw the curve we found if(nsPathIter::eLINE == curveType){ DrawStdLine(NSToCoordRound(thecurve.mAnc1.x),NSToCoordRound(thecurve.mAnc1.y),NSToCoordRound(thecurve.mAnc2.x),NSToCoordRound(thecurve.mAnc2.y)); } else { thecurve.SubDivide(this); } } // Release temporary storage if necessary if (pp0 != pts) delete [] pp0; return NS_OK; } #define MAXPATHSIZE 1000 /** --------------------------------------------------- * See documentation in nsIRenderingContext.h * @update 3/29/00 dwc */ NS_IMETHODIMP nsRenderingContextImpl::FillPath(nsPathPoint aPointArray[],PRInt32 aNumPts) { PRInt32 i; nsPathPoint pts[20]; nsPathPoint *pp0,*np=0,*pp; QBezierCurve thecurve; nsPathIter::eSegType curveType; nsPoint thePath[MAXPATHSIZE]; PRInt16 curPoint=0; // Transform the points first if (aNumPts > 20){ pp0 = new nsPathPoint[aNumPts]; } else { pp0 = &pts[0]; } pp = pp0; np = &aPointArray[0]; for ( i= 0; i < aNumPts; i++,np++,pp++){ pp->x = np->x; pp->y = np->y; pp->mIsOnCurve = np->mIsOnCurve; mTranMatrix->TransformCoord((int*)&pp->x,(int*)&pp->y); } nsPathIter thePathIter (pp0,aNumPts); while ( thePathIter.NextSeg(thecurve,curveType) ) { // build a polygon with the points if(nsPathIter::eLINE == curveType){ thePath[curPoint++].MoveTo(NSToCoordRound(thecurve.mAnc1.x),NSToCoordRound(thecurve.mAnc1.y)); thePath[curPoint++].MoveTo(NSToCoordRound(thecurve.mAnc2.x),NSToCoordRound(thecurve.mAnc2.y)); } else { thecurve.SubDivide(thePath,&curPoint); } } this->FillStdPolygon(thePath,curPoint); // Release temporary storage if necessary if (pp0 != pts) delete [] pp0; return NS_OK; } /** --------------------------------------------------- * See documentation in nsRenderingContextImpl.h * @update 3/29/00 dwc */ NS_IMETHODIMP nsRenderingContextImpl::RasterPolygon(const nsPoint aPointArray[],PRInt32 aNumPts) { PRInt32 k,y0,y1,y,i,j,xl,xr,extra=0; PRInt32 *ind; nsPoint pts[20]; nsPoint *pp,*pp0; const nsPoint *np; if (aNumPts<=0) return NS_OK; #ifdef XP_WIN extra = 1; #endif // Transform the points first if (aNumPts > 20){ pp0 = new nsPoint[aNumPts]; } else { pp0 = &pts[0]; } pp = pp0; np = &aPointArray[0]; for ( i= 0; i < aNumPts; i++,np++,pp++){ pp->x = np->x; pp->y = np->y; mTranMatrix->TransformCoord((PRInt32*)&pp->x,(PRInt32*)&pp->y); } ind = new PRInt32[aNumPts]; mActive = new Edge[aNumPts]; gPts = pp0; // create y-sorted array of indices ind[k] into vertex list for (k=0; k0 ? i-1 : aNumPts-1; if (pp0[j].y <= y-.5) cdelete(j); else if (pp0[j].y > y+.5) cinsert(j, y,pp0, aNumPts); j = i y+.5) cinsert(i, y,pp0, aNumPts); } // sort active edge list by active[j].x qsort(mActive, mAct, sizeof mActive[0], compare_active); // draw horizontal segments for scanline y for (j=0; j=mAct) return; mAct--; memcpy(&mActive[j], &mActive[j+1],(mAct-j)*sizeof mActive[0]); } /**------------------------------------------------------------------- * append edge i to end of active list * @update dc 12/06/1999 */ void nsRenderingContextImpl::cinsert(PRInt32 i,PRInt32 y,const nsPoint aPointArray[],PRInt32 aNumPts) { PRInt32 j; double dx; const nsPoint *p, *q; j = ix-(double)p->x)/((double)q->y-(double)p->y); mActive[mAct].x = dx*(y+.5-(double)p->y)+(double)p->x; mActive[mAct].i = i; mAct++; } NS_IMETHODIMP nsRenderingContextImpl::GetBackbuffer(const nsRect &aRequestedSize, const nsRect &aMaxSize, nsDrawingSurface &aBackbuffer) { // Default implementation assumes the backbuffer will be cached. // If the platform implementation does not require the backbuffer to // be cached override this method and make the following call instead: // AllocateBackbuffer(aRequestedSize, aMaxSize, aBackbuffer, PR_FALSE); return AllocateBackbuffer(aRequestedSize, aMaxSize, aBackbuffer, PR_TRUE); } nsresult nsRenderingContextImpl::AllocateBackbuffer(const nsRect &aRequestedSize, const nsRect &aMaxSize, nsDrawingSurface &aBackbuffer, PRBool aCacheBackbuffer) { nsRect newBounds; nsresult rv = NS_OK; if (! aCacheBackbuffer) { newBounds = aRequestedSize; } else { GetDrawingSurfaceSize(aMaxSize, aRequestedSize, newBounds); } if ((nsnull == gBackbuffer) || (gBackbufferBounds.width != newBounds.width) || (gBackbufferBounds.height != newBounds.height)) { if (gBackbuffer) { //destroy existing DS DestroyDrawingSurface(gBackbuffer); gBackbuffer = nsnull; } rv = CreateDrawingSurface(newBounds, 0, gBackbuffer); // printf("Allocating a new drawing surface %d %d\n", newBounds.width, newBounds.height); if (NS_SUCCEEDED(rv)) { gBackbufferBounds = newBounds; SelectOffScreenDrawingSurface(gBackbuffer); } else { gBackbufferBounds.SetRect(0,0,0,0); gBackbuffer = nsnull; } } else { SelectOffScreenDrawingSurface(gBackbuffer); float p2t; nsCOMPtr dx; GetDeviceContext(*getter_AddRefs(dx)); p2t = dx->DevUnitsToAppUnits(); nsRect bounds = aRequestedSize; bounds *= p2t; PRBool clipEmpty; SetClipRect(bounds, nsClipCombine_kReplace, clipEmpty); } aBackbuffer = gBackbuffer; return rv; } NS_IMETHODIMP nsRenderingContextImpl::ReleaseBackbuffer(void) { // If the platform does not require the backbuffer to be cached // override this method and call DestroyCachedBackbuffer return NS_OK; } NS_IMETHODIMP nsRenderingContextImpl::DestroyCachedBackbuffer(void) { if (gBackbuffer) { DestroyDrawingSurface(gBackbuffer); gBackbuffer = nsnull; } return NS_OK; } NS_IMETHODIMP nsRenderingContextImpl::UseBackbuffer(PRBool* aUseBackbuffer) { *aUseBackbuffer = PR_TRUE; return NS_OK; } PRBool nsRenderingContextImpl::RectFitsInside(const nsRect& aRect, PRInt32 aWidth, PRInt32 aHeight) const { if (aRect.width > aWidth) return (PR_FALSE); if (aRect.height > aHeight) return (PR_FALSE); return PR_TRUE; } PRBool nsRenderingContextImpl::BothRectsFitInside(const nsRect& aRect1, const nsRect& aRect2, PRInt32 aWidth, PRInt32 aHeight, nsRect& aNewSize) const { if (PR_FALSE == RectFitsInside(aRect1, aWidth, aHeight)) { return PR_FALSE; } if (PR_FALSE == RectFitsInside(aRect2, aWidth, aHeight)) { return PR_FALSE; } aNewSize.width = aWidth; aNewSize.height = aHeight; return PR_TRUE; } void nsRenderingContextImpl::GetDrawingSurfaceSize(const nsRect& aMaxBackbufferSize, const nsRect& aRequestedSize, nsRect& aNewSize) { CalculateDiscreteSurfaceSize(aMaxBackbufferSize, aRequestedSize, aNewSize); aNewSize.MoveTo(aRequestedSize.x, aRequestedSize.y); } void nsRenderingContextImpl::CalculateDiscreteSurfaceSize(const nsRect& aMaxBackbufferSize, const nsRect& aRequestedSize, nsRect& aSurfaceSize) { // Get the height and width of the screen PRInt32 height; PRInt32 width; nsCOMPtr dx; GetDeviceContext(*getter_AddRefs(dx)); dx->GetDeviceSurfaceDimensions(width, height); float devUnits; devUnits = dx->DevUnitsToAppUnits(); PRInt32 screenHeight = NSToIntRound(float( height) / devUnits ); PRInt32 screenWidth = NSToIntRound(float( width) / devUnits ); // These tests must go from smallest rectangle to largest rectangle. // 1/8 screen if (BothRectsFitInside(aRequestedSize, aMaxBackbufferSize, screenWidth / 8, screenHeight / 8, aSurfaceSize)) { return; } // 1/4 screen if (BothRectsFitInside(aRequestedSize, aMaxBackbufferSize, screenWidth / 4, screenHeight / 4, aSurfaceSize)) { return; } // 1/2 screen if (BothRectsFitInside(aRequestedSize, aMaxBackbufferSize, screenWidth / 2, screenHeight / 2, aSurfaceSize)) { return; } // 3/4 screen if (BothRectsFitInside(aRequestedSize, aMaxBackbufferSize, (screenWidth * 3) / 4, (screenHeight * 3) / 4, aSurfaceSize)) { return; } // 3/4 screen width full screen height if (BothRectsFitInside(aRequestedSize, aMaxBackbufferSize, (screenWidth * 3) / 4, screenHeight, aSurfaceSize)) { return; } // Full screen if (BothRectsFitInside(aRequestedSize, aMaxBackbufferSize, screenWidth, screenHeight, aSurfaceSize)) { return; } // Bigger than Full Screen use the largest request every made. if (BothRectsFitInside(aRequestedSize, aMaxBackbufferSize, gLargestRequestedSize.width, gLargestRequestedSize.height, aSurfaceSize)) { return; } else { gLargestRequestedSize.width = PR_MAX(aRequestedSize.width, aMaxBackbufferSize.width); gLargestRequestedSize.height = PR_MAX(aRequestedSize.height, aMaxBackbufferSize.height); aSurfaceSize.width = gLargestRequestedSize.width; aSurfaceSize.height = gLargestRequestedSize.height; // printf("Expanding the largested requested size to %d %d\n", gLargestRequestedSize.width, gLargestRequestedSize.height); } } /** * Let the device context know whether we want text reordered with * right-to-left base direction */ NS_IMETHODIMP nsRenderingContextImpl::SetRightToLeftText(PRBool aIsRTL) { return NS_OK; } /** --------------------------------------------------- * See documentation in nsRenderingContextImpl.h * @update 3/29/00 dwc */ void QBezierCurve::SubDivide(nsIRenderingContext *aRenderingContext) { QBezierCurve curve1,curve2; float fx,fy,smag; // divide the curve into 2 pieces MidPointDivide(&curve1,&curve2); // for now to fix the build fx = (float) fabs(curve1.mAnc2.x - this->mCon.x); fy = (float) fabs(curve1.mAnc2.y - this->mCon.y); //smag = fx+fy-(PR_MIN(fx,fy)>>1); smag = fx*fx + fy*fy; if (smag>1){ // split the curve again curve1.SubDivide(aRenderingContext); curve2.SubDivide(aRenderingContext); }else{ // draw the curve #ifdef DEBUGCURVE printf("LINE 1- %d,%d %d,%d\n",NSToCoordRound(curve1.mAnc1.x),NSToCoordRound(curve1.mAnc1.y), NSToCoordRound(curve1.mAnc1.x),NSToCoordRound(curve1.mAnc1.y)); printf("LINE 2- %d,%d %d,%d\n",NSToCoordRound(curve1.mAnc2.x),NSToCoordRound(curve1.mAnc2.y), NSToCoordRound(curve2.mAnc2.x),NSToCoordRound(curve2.mAnc2.y)); #endif aRenderingContext->DrawStdLine(NSToCoordRound(curve1.mAnc1.x),NSToCoordRound(curve1.mAnc1.y),NSToCoordRound(curve1.mAnc2.x),NSToCoordRound(curve1.mAnc2.y)); aRenderingContext->DrawStdLine(NSToCoordRound(curve1.mAnc2.x),NSToCoordRound(curve1.mAnc2.y),NSToCoordRound(curve2.mAnc2.x),NSToCoordRound(curve2.mAnc2.y)); } } /** --------------------------------------------------- * See documentation in nsRenderingContextImpl.h * @update 3/29/00 dwc */ void QBezierCurve::DebugPrint() { printf("CURVE COORDINATES\n"); printf("Anchor 1 %f %f\n",mAnc1.x,mAnc1.y); printf("Control %f %f\n",mCon.x,mCon.y); printf("Anchor %f %f\n",mAnc2.x,mAnc2.y); } /** --------------------------------------------------- * See documentation in nsRenderingContextImpl.h * @update 3/29/00 dwc */ void QBezierCurve::SubDivide(nsPoint aThePoints[],PRInt16 *aNumPts) { QBezierCurve curve1,curve2; float fx,fy,smag; // divide the curve into 2 pieces MidPointDivide(&curve1,&curve2); // for now to fix the build fx = (float) fabs(curve1.mAnc2.x - this->mCon.x); fy = (float) fabs(curve1.mAnc2.y - this->mCon.y); //smag = fx+fy-(PR_MIN(fx,fy)>>1); smag = fx*fx + fy*fy; if (smag>1){ // split the curve again curve1.SubDivide(aThePoints,aNumPts); curve2.SubDivide(aThePoints,aNumPts); }else{ // draw the curve aThePoints[(*aNumPts)++].MoveTo(NSToCoordRound(curve1.mAnc1.x),NSToCoordRound(curve1.mAnc1.y)); aThePoints[(*aNumPts)++].MoveTo(NSToCoordRound(curve1.mAnc2.x),NSToCoordRound(curve1.mAnc2.y)); aThePoints[(*aNumPts)++].MoveTo(NSToCoordRound(curve2.mAnc2.x),NSToCoordRound(curve2.mAnc2.y)); #ifdef DEBUGCURVE printf("LINE 1- %d,%d %d,%d\n",NSToCoordRound(curve1.mAnc1.x),NSToCoordRound(curve1.mAnc1.y), NSToCoordRound(curve1.mAnc1.x),NSToCoordRound(curve1.mAnc1.y)); printf("LINE 2- %d,%d %d,%d\n",NSToCoordRound(curve1.mAnc2.x),NSToCoordRound(curve1.mAnc2.y), NSToCoordRound(curve2.mAnc2.x),NSToCoordRound(curve2.mAnc2.y)); #endif } } /** --------------------------------------------------- * See documentation in nsRenderingContextImpl.h * @update 4/27/2000 dwc */ void QBezierCurve::MidPointDivide(QBezierCurve *A,QBezierCurve *B) { float c1x,c1y,c2x,c2y; nsFloatPoint a1; c1x = (float) ((mAnc1.x+mCon.x)/2.0); c1y = (float) ((mAnc1.y+mCon.y)/2.0); c2x = (float) ((mAnc2.x+mCon.x)/2.0); c2y = (float) ((mAnc2.y+mCon.y)/2.0); a1.x = (float) ((c1x + c2x)/2.0); a1.y = (float) ((c1y + c2y)/2.0); // put the math into our 2 new curves A->mAnc1 = this->mAnc1; A->mCon.x = c1x; A->mCon.y = c1y; A->mAnc2 = a1; B->mAnc1 = a1; B->mCon.x = c2x; B->mCon.y = c2y; B->mAnc2 = this->mAnc2; } /** --------------------------------------------------- * See documentation in nsRenderingContextImpl.h * @update 4/27/2000 dwc */ nsPathIter::nsPathIter() { mCurPoint = 0; mNumPoints = 0; mThePath = 0; } /** --------------------------------------------------- * See documentation in nsRenderingContextImpl.h * @update 4/27/2000 dwc */ nsPathIter::nsPathIter(nsPathPoint* aThePath,PRUint32 aNumPts) { mCurPoint = 0; mNumPoints = aNumPts; mThePath = aThePath; } /** --------------------------------------------------- * See documentation in nsRenderingContextImpl.h * @update 4/27/2000 dwc */ PRBool nsPathIter::NextSeg(QBezierCurve& TheSegment,eSegType& aCurveType) { PRInt8 code=0,number=1; PRBool result = PR_TRUE; nsPathPoint *pt1,*pt2,*pt3; float avx,avy,av1x,av1y; if ( mCurPoint < mNumPoints) { // 1st point pt1 = &(mThePath[mCurPoint]); if(PR_TRUE == pt1->mIsOnCurve) { code += 0x04; } // 2nd point if ( (mCurPoint+1) < mNumPoints) { number++; pt2 = &(mThePath[mCurPoint+1]); if(PR_TRUE == pt2->mIsOnCurve) { code += 0x02; } // 3rd point if( (mCurPoint+2) < mNumPoints) { number++; pt3 = &(mThePath[mCurPoint+2]); if(PR_TRUE == pt3->mIsOnCurve) { code += 0x01; } // have all three points.. switch(code) { case 07: // 111 case 06: // 110 TheSegment.SetPoints(pt1->x,pt1->y,0.0,0.0,pt2->x,pt2->y); aCurveType = eLINE; mCurPoint++; break; case 05: // 101 TheSegment.SetPoints(pt1->x,pt1->y,pt2->x,pt2->y,pt3->x,pt3->y); aCurveType = eQCURVE; mCurPoint+=2; break; case 04: // 100 avx = (float)((pt2->x+pt3->x)/2.0); avy = (float)((pt2->y+pt3->y)/2.0); TheSegment.SetPoints(pt1->x,pt1->y,pt2->x,pt2->y,avx,avy); aCurveType = eQCURVE; mCurPoint++; case 03: // 011 case 02: // 010 TheSegment.SetPoints(pt1->x,pt1->y,0.0,0.0,pt2->x,pt2->y); aCurveType = eLINE; mCurPoint++; case 01: // 001 avx = (float)((pt1->x+pt2->x)/2.0); avy = (float)((pt1->y+pt2->y)/2.0); TheSegment.SetPoints(avx,avy,pt2->x,pt3->y,pt2->x,pt3->y); aCurveType = eQCURVE; mCurPoint+=2; case 00: // 000 avx = (float)((pt1->x+pt2->x)/2.0); avy = (float)((pt1->y+pt2->y)/2.0); av1x = (float)((pt2->x+pt3->x)/2.0); av1y = (float)((pt2->y+pt3->y)/2.0); TheSegment.SetPoints(avx,avy,pt2->x,pt2->y,av1x,av1y); default: break; } } else { // have two points.. draw a line TheSegment.SetPoints(pt1->x,pt1->y,0.0,0.0,pt2->x,pt2->y); aCurveType = eLINE; mCurPoint++; } } else { // just have one point result = PR_FALSE; } } else { // all finished result = PR_FALSE; } return result; } #include "imgIContainer.h" #include "gfxIImageFrame.h" #include "nsIInterfaceRequestor.h" #include "nsIInterfaceRequestorUtils.h" /* [noscript] void drawImage (in imgIContainer aImage, [const] in nsRect aSrcRect, [const] in nsPoint aDestPoint); */ NS_IMETHODIMP nsRenderingContextImpl::DrawImage(imgIContainer *aImage, const nsRect * aSrcRect, const nsPoint * aDestPoint) { nsPoint pt; nsRect sr; float fX = float(aDestPoint->x), fY = float(aDestPoint->y); mTranMatrix->Transform(&fX, &fY); pt.x = NSToCoordRound(fX); pt.y = NSToCoordRound(fY); sr = *aSrcRect; mTranMatrix->TransformCoord(&sr.x, &sr.y, &sr.width, &sr.height); sr.x = aSrcRect->x; sr.y = aSrcRect->y; mTranMatrix->TransformNoXLateCoord(&sr.x, &sr.y); nsCOMPtr iframe; aImage->GetCurrentFrame(getter_AddRefs(iframe)); if (!iframe) return NS_ERROR_FAILURE; nsCOMPtr img(do_GetInterface(iframe)); if (!img) return NS_ERROR_FAILURE; nsIDrawingSurface *surface = nsnull; GetDrawingSurface((void**)&surface); if (!surface) return NS_ERROR_FAILURE; // For Bug 87819 // iframe may want image to start at different position, so adjust nsRect iframeRect; iframe->GetRect(iframeRect); if (iframeRect.y > 0) { sr.y -= iframeRect.y; if (sr.y < 0) { pt.y = pt.y - sr.y; sr.height = sr.height + sr.y; if (sr.height < 0) return NS_OK; sr.y = 0; } else if (sr.y > iframeRect.height) { return NS_OK; } } if (iframeRect.x > 0) { sr.x -= iframeRect.x; if (sr.x < 0) { pt.x = pt.x - sr.x; sr.width = sr.width + sr.x; if (sr.width < 0) return NS_OK; sr.x = 0; } else if (sr.x > iframeRect.width) { return NS_OK; } } return img->Draw(*this, surface, sr.x, sr.y, sr.width, sr.height, pt.x, pt.y, sr.width, sr.height); } /* [noscript] void drawScaledImage (in imgIContainer aImage, [const] in nsRect aSrcRect, [const] in nsRect aDestRect); */ NS_IMETHODIMP nsRenderingContextImpl::DrawScaledImage(imgIContainer *aImage, const nsRect * aSrcRect, const nsRect * aDestRect) { nsRect dr; nsRect sr; dr = *aDestRect; mTranMatrix->TransformCoord(&dr.x, &dr.y, &dr.width, &dr.height); sr = *aSrcRect; mTranMatrix->TransformCoord(&sr.x, &sr.y, &sr.width, &sr.height); if (sr.width <= 0 || sr.height <= 0 || dr.width <= 0 || dr.height <= 0) return NS_OK; sr.x = aSrcRect->x; sr.y = aSrcRect->y; mTranMatrix->TransformNoXLateCoord(&sr.x, &sr.y); nsCOMPtr iframe; aImage->GetCurrentFrame(getter_AddRefs(iframe)); if (!iframe) return NS_ERROR_FAILURE; nsCOMPtr img(do_GetInterface(iframe)); if (!img) return NS_ERROR_FAILURE; nsIDrawingSurface *surface = nsnull; GetDrawingSurface((void**)&surface); if (!surface) return NS_ERROR_FAILURE; // For Bug 87819 // iframe may want image to start at different position, so adjust nsRect iframeRect; iframe->GetRect(iframeRect); if (iframeRect.x > 0) { float xScaleRatio = float(dr.width) / sr.width; sr.x -= iframeRect.x; if (sr.x < 0) { dr.x -= NSToIntRound(sr.x * xScaleRatio); sr.width += sr.x; dr.width += NSToIntRound(sr.x * xScaleRatio); if (sr.width <= 0 || dr.width <= 0) return NS_OK; sr.x = 0; } else if (sr.x > iframeRect.width) { return NS_OK; } } if (iframeRect.y > 0) { float yScaleRatio = float(dr.height) / sr.height; // adjust for offset sr.y -= iframeRect.y; if (sr.y < 0) { dr.y -= NSToIntRound(sr.y * yScaleRatio); sr.height += sr.y; dr.height += NSToIntRound(sr.y * yScaleRatio); if (sr.height <= 0 || dr.height <= 0) return NS_OK; sr.y = 0; } else if (sr.y > iframeRect.height) { return NS_OK; } } return img->Draw(*this, surface, sr.x, sr.y, sr.width, sr.height, dr.x, dr.y, dr.width, dr.height); } /* [noscript] void drawTile (in imgIContainer aImage, in nscoord aXImageStart, in nscoord aYImageStart, [const] in nsRect aTargetRect); */ NS_IMETHODIMP nsRenderingContextImpl::DrawTile(imgIContainer *aImage, nscoord aXImageStart, nscoord aYImageStart, const nsRect * aTargetRect) { nsRect dr(*aTargetRect); mTranMatrix->TransformCoord(&dr.x, &dr.y, &dr.width, &dr.height); mTranMatrix->TransformCoord(&aXImageStart, &aYImageStart); // may have become empty due to transform shinking small number to 0 if (dr.IsEmpty()) return NS_OK; nscoord width, height; aImage->GetWidth(&width); aImage->GetHeight(&height); if (width == 0 || height == 0) return NS_OK; nscoord xOffset = (dr.x - aXImageStart) % width; nscoord yOffset = (dr.y - aYImageStart) % height; nsCOMPtr iframe; aImage->GetCurrentFrame(getter_AddRefs(iframe)); if (!iframe) return NS_ERROR_FAILURE; nsCOMPtr img(do_GetInterface(iframe)); if (!img) return NS_ERROR_FAILURE; nsIDrawingSurface *surface = nsnull; GetDrawingSurface((void**)&surface); if (!surface) return NS_ERROR_FAILURE; /* bug 113561 - frame can be smaller than container */ nsRect iframeRect; iframe->GetRect(iframeRect); PRInt32 padx = width - iframeRect.width; PRInt32 pady = height - iframeRect.height; return img->DrawTile(*this, surface, xOffset - iframeRect.x, yOffset - iframeRect.y, padx, pady, dr); } NS_IMETHODIMP nsRenderingContextImpl::FlushRect(const nsRect& aRect) { return NS_OK; } NS_IMETHODIMP nsRenderingContextImpl::FlushRect(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight) { return NS_OK; }