graphicsdeviceinterface/bitgdi/sbit/ELLIPSE.CPP
changeset 0 5d03bc08d59c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graphicsdeviceinterface/bitgdi/sbit/ELLIPSE.CPP	Tue Feb 02 01:47:50 2010 +0200
@@ -0,0 +1,405 @@
+// Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+//
+
+#include <bitstd.h>
+#include <bitdev.h>
+#include "BITPANIC.H"
+#include <bitdraw.h>
+#include <graphics/fbsrasterizer.h>
+
+/*
+ * TEllipse
+ */
+ 
+ /**
+ Initialises the values of the ellipse so that it conforms to a rectangle entered as a parameter.
+ @param aRect the rectangle within which the ellipse is drawn
+ */
+EXPORT_C void TEllipse::Construct(const TRect& aRect)
+	{
+	TInt width=aRect.Width();
+	TInt height=aRect.Height();
+	iA=(width-1)>>1;
+	iB=(height-1)>>1;
+	iXAdj=(width+1)&1;
+	iYAdj=(height+1)&1;
+	iOffset=aRect.iTl;
+	iX=0;
+	iY=iB;
+	iASquared=iA*iA;
+	iBSquared=iB*iB;
+	iASquBSqu=iASquared*iBSquared;
+	iD1=iBSquared-iASquared*iB+(iASquared>>1);
+	if(width<=0 || height<=0)
+		iStatus=EComplete;
+	else if(width<=2 || height<=2)
+		iStatus=ELine;
+	else if(iA+iXAdj==0 || iB+iYAdj==0)
+		iStatus=EComplete;
+	else
+		iStatus=EInitialised;
+	}
+
+/**
+Does the next stage in producing an ellipse by taking four points (the corners of 
+the rectangle the ellipse should fill) as parameters. Updates TEllipse status 
+accordingly and calls <code>Output(aTopLeft,aTopRight,aBottomLeft,aBottomRight)</code>.
+@param aTopLeft Top left corner of rectangle 
+@param aTopRight Top right corner of rectangle
+@param aBottomLeft Bottom left corner of rectangle
+@param aBottomRight Bottom right corner of rectangle
+@return TBool ETrue if step completed successfully.
+*/
+EXPORT_C TBool TEllipse::SingleStep(TPoint& aTopLeft,TPoint& aTopRight,
+									TPoint& aBottomLeft,TPoint& aBottomRight)
+	{
+	TBool ret=EFalse;
+	if(iStatus==EFirstSector)
+		{
+		if(iD1<0)
+			iD1+=iBSquared*((iX<<1)+3);
+		else if(iY>0)
+			{
+			iD1+=iBSquared*((iX<<1)+3)+iASquared*(2-(iY<<1));
+			iY--;
+			}
+		iX++;
+		ret=Output(aTopLeft,aTopRight,aBottomLeft,aBottomRight);
+		if(iStatus==EComplete && iX<iA)
+			{
+			iStatus=EFirstSector;
+			return(EFalse);
+			}
+		if(iASquared*iY<=iBSquared*(iX+1) && ret==EFalse)
+			{
+			iStatus=ESecondSector;
+			iD2=-iASquBSqu+iBSquared*iX*iX+iASquared*(iY-1)*(iY-1);
+			}
+		return(ret);
+		}
+	if(iStatus==ESecondSector)
+		{
+		if(iD2<0)
+			{
+			iD2+=iBSquared*((iX<<1)+2)+iASquared*(3-(iY<<1));
+			iX++;
+			}
+		else
+			iD2+=iASquared*(3-(iY<<1));
+		iY--;
+		return(Output(aTopLeft,aTopRight,aBottomLeft,aBottomRight));
+		}
+	if(iStatus==ELine)
+		{
+		ret=Output(aTopLeft,aTopRight,aBottomLeft,aBottomRight);
+		if(iA==0)
+			iY--;
+		else
+			{
+			iX++;
+			if(iX>iA+iXAdj) ret=ETrue;
+			else
+				{
+				iStatus=ELine;
+				ret=EFalse;
+				}
+			}
+		return(ret);
+		}
+	if(iStatus==EInitialised)
+		{
+		iStatus=EFirstSector;
+		return(Output(aTopLeft,aTopRight,aBottomLeft,aBottomRight));
+		}
+	Output(aTopLeft,aTopRight,aBottomLeft,aBottomRight);
+	return(ETrue);
+	}
+
+/**
+Sets the absolute points that define the ellipse as calculated using its iOffset 
+from the origin and using the half width and half height of the rectangle iA and iB.
+@param aTopLeft The absolute (x,y) position for the top left point.
+@param aTopRight The absolute (x,y) position for the top right point.
+@param aBottomLeft The absolute (x,y) position for the bottom left point.
+@param aBottomRight The absolute (x,y) position for the bottom right point.
+@return TBool ETrue if a valid rectangle is produced, else EFalse. Also sets
+iStatus to EComplete.
+*/
+EXPORT_C TBool TEllipse::Output(TPoint& aTopLeft,TPoint& aTopRight,
+								TPoint& aBottomLeft,TPoint& aBottomRight)
+	{
+	TInt lx=iA-iX+iOffset.iX;
+	TInt ty=iB-iY+iOffset.iY;
+	TInt rx=iA+iX+iXAdj+iOffset.iX;
+	TInt by=iB+iY+iYAdj+iOffset.iY;
+	aTopLeft.SetXY(lx,ty);
+	aTopRight.SetXY(rx,ty);
+	aBottomLeft.SetXY(lx,by);
+	aBottomRight.SetXY(rx,by);
+	if(iY<=0)
+		{
+		iStatus=EComplete;
+		if(iYAdj==0 || ty>by)
+			return(ETrue);
+		}
+	return(EFalse);
+	}
+
+/**
+By analysing the current state of the ellipse the process is taken to the next appropriate step.
+If iStatus = EInitialised only one step will be taken, if the ellipse is already semi constructed then 
+it will be taken to completion. Takes in four point parameters that defines the rectangle in order to pass to 
+SingleStep(aTopLeft,aTopRight,aBottomLeft,aBottomRight).
+@param aTopLeft Top left corner of rectangle 
+@param aTopRight Top right corner of rectangle
+@param aBottomLeft Bottom left corner of rectangle
+@param aBottomRight Bottom right corner of rectangle
+@return TBool ETrue if a valid rectangle is produced, else EFalse.
+*/
+EXPORT_C TBool TEllipse::NextStep(TPoint& aTopLeft,TPoint& aTopRight,
+								  TPoint& aBottomLeft,TPoint& aBottomRight)
+	{
+	if(iStatus==EInitialised)
+		return(SingleStep(aTopLeft,aTopRight,aBottomLeft,aBottomRight));
+	TInt prevlev=iY;
+	TBool ret;
+	do
+		ret=SingleStep(aTopLeft,aTopRight,aBottomLeft,aBottomRight);
+	while(prevlev==iY && ret==EFalse);
+	return(ret);
+	}
+
+/**
+Constructs an ellipse from the rectangle which it is given and assesses the 
+points position with regard to the ellipse and where they intersect. 
+@param aRect The rectangle within which the ellipse is drawn.
+@param aPoint A point to compare with the ellipse to determine if intersection occurs. 
+@return TPoint The point is set to the corner which the intersection is nearest to.
+*/
+EXPORT_C TPoint TEllipse::Intersection(const TRect& aRect,const TPoint& aPoint)
+	{
+	Construct(aRect);					//constructs the rect (an elipse object)
+	TPoint centre=aRect.Center();		//centre of ellipse
+	TPoint ptcpy(aPoint);				
+	ptcpy-=iOffset;						//ptcpy = aPoint - iOffset - TPoint(iA,iB)	//radius from centre of ellipse		
+	ptcpy-=TPoint(iA,iB);				
+	TPoint pt[4],opt[4];			
+	TInt mpt[4],ompt[4];
+	TInt count=0;
+	for(;count<4;count++)
+		ompt[count]=KMaxTInt;			//fills ompt 1->4 with KMaxTInt
+	while(SingleStep(pt[0],pt[1],pt[2],pt[3])==EFalse) 	//creates a complete ellipse with pts as rect
+		for(count=0;count<4;count++)
+			{
+			mpt[count]=Abs((pt[count].iY-iOffset.iY-iB)*(ptcpy.iX)-(ptcpy.iY)*(pt[count].iX-iOffset.iX-iA));
+			if(mpt[count]<ompt[count]) //use the larger number set.
+				{
+				ompt[count]=mpt[count];
+				opt[count]=pt[count];
+				}						
+			}
+	if(pt[0].iY==pt[2].iY)	//if it is horizontal
+		for(count=0;count<4;count++)
+			{
+			mpt[count]=Abs((pt[count].iY-iOffset.iY-iB)*(ptcpy.iX)-(ptcpy.iY)*(pt[count].iX-iOffset.iX-iA));
+			if(mpt[count]<ompt[count]) //use the larger number set.
+				{
+				ompt[count]=mpt[count];
+				opt[count]=pt[count];
+				}
+			}
+	if(ptcpy.iX<0 && ptcpy.iY<0)	//if point is further left and higher than centre of rect
+		return(opt[0]);
+	if(ptcpy.iY<0)			//if point is higher than centre of rect
+		return(opt[1]);
+	if(ptcpy.iX<0)			//if point is further left than centre of rect
+		return(opt[2]);
+	if(aPoint.iX<centre.iX && aPoint.iY<centre.iY)	//if point is further left and higher than centre of rect
+		return(opt[0]);
+	if(aPoint.iY<centre.iY)	//if point is higher than centre of rect
+		return(opt[1]);
+	if(aPoint.iX<centre.iX)	//if point is further left than centre of rect
+		return(opt[2]);
+	return(opt[3]);			//else 
+	}
+
+//
+// Ellipse drawing
+//
+
+/**
+Draws and fills an ellipse.
+
+The function provides a concrete implementation of the pure virtual
+function <code>CGraphicsContext::DrawEllipse()</code>. The function
+behaviour is the same as documented in that class.
+*/
+EXPORT_C void CFbsBitGc::DrawEllipse(const TRect& aRect)
+	{
+	if(CheckDevice(aRect)) return;
+	TRect rcpy(aRect);
+	rcpy.Move(iOrigin);
+	iDevice->TruncateRect(rcpy);
+	TRect clippedRect(rcpy);
+	clippedRect.Grow((iPenSize.iWidth>>1)+1,(iPenSize.iHeight>>1)+1);
+	if(UserClipRect(clippedRect)) return;
+	SetupDevice();
+	iDevice->DrawingBegin(&iBrushBitmap);
+	CFbsRasterizer* brushRasterizer = PrepareRasterizerForExtendedBitmap(iBrushBitmap);
+	if(iBrushStyle!=ENullBrush)
+		EllipseFill(rcpy);
+	if(iPenStyle!=ENullPen)
+		{
+		if(iPenSize.iWidth>1 && iPenSize.iHeight>1)
+			EllipseOutlineWide(rcpy);
+		else
+			if(iPenSize.iWidth==1 || iPenSize.iHeight==1)
+				EllipseOutline(rcpy);
+		}
+	if (brushRasterizer)
+		{
+		brushRasterizer->EndBitmap(iBrushBitmap.SerialNumber());
+		}
+	iDevice->DrawingEnd(&iBrushBitmap);
+	}
+
+void CFbsBitGc::EllipseOutline(const TRect& aRect)
+	{
+	CFbsDrawDevice* drawDevice = iDevice->iDrawDevice;
+	TPoint tl,tr,bl,br;
+	AddRect(aRect);
+#if defined(_DEBUG)
+	TRect deviceDestRect;
+	drawDevice->GetDrawRect(deviceDestRect);
+#endif
+	for(TInt count=0;count<iDefaultRegionPtr->Count();count++)
+		{
+		iClipRect=(*iDefaultRegionPtr)[count];
+		if(!iClipRect.Intersects(aRect))
+			continue;
+		iClipRect.Intersection(aRect);
+		if(UserClipRect(iClipRect)) continue;
+		BG_ASSERT_DEBUG(iClipRect.iTl.iX >= deviceDestRect.iTl.iX, EBitgdiPanicOutOfBounds);
+		BG_ASSERT_DEBUG(iClipRect.iTl.iY >= deviceDestRect.iTl.iY, EBitgdiPanicOutOfBounds);
+		BG_ASSERT_DEBUG(iClipRect.iBr.iX <= deviceDestRect.iBr.iX, EBitgdiPanicOutOfBounds);
+		BG_ASSERT_DEBUG(iClipRect.iBr.iY <= deviceDestRect.iBr.iY, EBitgdiPanicOutOfBounds);
+		TEllipse ellipse;
+		ellipse.Construct(aRect);
+		TInt pattern=0;
+		while(!ellipse.SingleStep(tl,tr,bl,br))
+			{
+			if(iPenStyle==CGraphicsContext::ESolidPen || (iDotMask&(1<<(pattern%iDotLength))))
+				{
+				if(tl.iY>=iClipRect.iTl.iY && tl.iY<iClipRect.iBr.iY)
+					{
+					if(tl.iX>=iClipRect.iTl.iX && tl.iX<iClipRect.iBr.iX)
+						drawDevice->WriteRgb(tl.iX,tl.iY,iPenColor,iDrawMode);
+					if(tr.iX>=iClipRect.iTl.iX && tr.iX<iClipRect.iBr.iX && tl.iX!=tr.iX)
+						drawDevice->WriteRgb(tr.iX,tr.iY,iPenColor,iDrawMode);
+					}
+				if(bl.iY>=iClipRect.iTl.iY && bl.iY<iClipRect.iBr.iY)
+					{
+					if(bl.iX>=iClipRect.iTl.iX && bl.iX<iClipRect.iBr.iX)
+						drawDevice->WriteRgb(bl.iX,bl.iY,iPenColor,iDrawMode);
+					if(br.iX>=iClipRect.iTl.iX && br.iX<iClipRect.iBr.iX && bl.iX!=br.iX)
+						drawDevice->WriteRgb(br.iX,br.iY,iPenColor,iDrawMode);
+					}
+				}
+			pattern++;
+			}
+		if(tl.iY==bl.iY && tl.iY>=iClipRect.iTl.iY && tl.iY<iClipRect.iBr.iY)
+			{
+			if(tl.iX>=iClipRect.iTl.iX && tl.iX<iClipRect.iBr.iX)
+				drawDevice->WriteRgb(tl.iX,tl.iY,iPenColor,iDrawMode);
+			if(tr.iX>=iClipRect.iTl.iX && tr.iX<iClipRect.iBr.iX && tl.iX!=tr.iX)
+				drawDevice->WriteRgb(tr.iX,tr.iY,iPenColor,iDrawMode);
+			}
+		drawDevice->UpdateRegion(iClipRect);
+		}
+	}
+
+void CFbsBitGc::EllipseOutlineWide(const TRect& aRect)
+	{
+	TRect rcpy(aRect);
+	TPoint tl,tr,bl,br;
+	TInt halfpenwidth=(iPenSize.iWidth+1)>>1;
+	TInt halfpenheight=(iPenSize.iHeight+1)>>1;
+	rcpy.Grow(halfpenwidth,halfpenheight);
+	AddRect(rcpy);
+	TInt dp=iDotParam;
+	for(TInt count=0;count<iDefaultRegionPtr->Count();count++)
+		{
+		iClipRect=(*iDefaultRegionPtr)[count];
+		if(!iClipRect.Intersects(rcpy))
+			continue;
+		iClipRect.Intersection(rcpy);
+		if(UserClipRect(iClipRect)) continue;
+		TEllipse ellipse;
+		ellipse.Construct(aRect);
+		iDotParam=Max(iPenSize.iWidth>>1,iPenSize.iHeight>>1);
+		while(!ellipse.SingleStep(tl,tr,bl,br))
+			{
+			PenDrawClipped(tl);
+			PenDrawClipped(tr);
+			PenDrawClipped(bl);
+			PenDrawClipped(br);
+			iDotParam+=iDotDirection;
+			}
+		if(tl.iY==bl.iY)
+			{
+			PenDrawClipped(tl);
+			PenDrawClipped(tr);
+			}
+		iDevice->iDrawDevice->UpdateRegion(iClipRect);
+		}
+	iDotParam=dp;
+	}
+
+// if iBrushBitmap is an extended bitmap, PrepareRasterizerForExtendedBitmap() must have been called before this method
+void CFbsBitGc::EllipseFill(const TRect& aRect)
+	{
+	TRect rcpy(aRect);
+	if(iPenSize.iWidth==0 || iPenSize.iHeight==0)
+		rcpy.Grow(1,1);
+	AddRect(aRect);
+	TPoint tl,tr,bl,br;
+	for(TInt count=0;count<iDefaultRegionPtr->Count();count++)
+		{
+		iClipRect=(*iDefaultRegionPtr)[count];
+		if(!iClipRect.Intersects(rcpy))
+			continue;
+		iClipRect.Intersection(rcpy);
+		if(UserClipRect(iClipRect)) continue;
+		TEllipse ellipse;
+		ellipse.Construct(rcpy);
+		while(!ellipse.NextStep(tl,tr,bl,br))
+			{
+			tl.iX++;
+			tr.iX--;
+			bl.iX++;
+			br.iX--;
+			ClipFillLine(tl,tr);
+			ClipFillLine(bl,br);
+			}
+		if(tl.iY==bl.iY)
+			{
+			tl.iX++;
+			tr.iX--;
+			ClipFillLine(tl,tr);
+			}
+		iDevice->iDrawDevice->UpdateRegion(iClipRect);
+		}
+	}
+