graphicsdeviceinterface/bitgdi/sbit/RECT.CPP
changeset 0 5d03bc08d59c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graphicsdeviceinterface/bitgdi/sbit/RECT.CPP	Tue Feb 02 01:47:50 2010 +0200
@@ -0,0 +1,497 @@
+// 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 <fntstore.h>
+#include <bitmap.h>
+#include <bitstd.h>
+#include <bitdev.h>
+#include "BITPANIC.H"
+#include <graphicsaccelerator.h>
+#include <bitdraw.h>
+#include <graphics/fbsrasterizer.h>
+
+/**
+Copies a rectangle.
+
+The function provides a concrete implementation of the pure virtual
+function <code>CBitmapContext::CopyRect()</code>. The function
+behaviour is the same as documented in that class.
+*/
+EXPORT_C void CFbsBitGc::CopyRect(const TPoint& aOffset,const TRect& aRect)
+	{
+	if(CheckDevice(aRect) || aRect.IsEmpty() || aOffset == TPoint(0,0))
+		return;
+
+	CFbsDrawDevice* drawDevice = iDevice->iDrawDevice;
+
+	TRect deviceRect;
+	drawDevice->GetDrawRect(deviceRect);
+	const TPoint back(TPoint(0,0)-aOffset);
+	TRect rcpy(aRect);
+	rcpy.Move(iOrigin);
+	rcpy.Intersection(deviceRect);
+	((TRegion*)iDefaultRegionPtr)->Sort(aOffset);
+
+	TRect clippedBoundingRect(rcpy);
+	clippedBoundingRect.Move(aOffset);
+	AddRect(clippedBoundingRect);
+	clippedBoundingRect.BoundingRect(rcpy);
+	if(!clippedBoundingRect.Intersects(iUserClipRect))
+		return;
+
+	SetupDevice();
+	iDevice->DrawingBegin();
+
+	const TInt limit=iDefaultRegionPtr->Count();
+	for(TInt count=0;count<limit;count++)
+		{
+		iClipRect=(*iDefaultRegionPtr)[count];
+		if(UserClipRect(iClipRect)) 
+			continue;
+		iClipRect.Move(back);
+		if(!iClipRect.Intersects(rcpy))
+			continue;
+
+		iClipRect.Intersection(rcpy);
+		TDrawMode drawMode = iDrawMode;
+		iDrawMode = EDrawModeWriteAlpha;
+		DoCopyRect(aOffset,iClipRect);
+		iDrawMode = drawMode; // restore the previous draw mode
+		iClipRect.Move(aOffset);
+		drawDevice->UpdateRegion(iClipRect);
+		}
+
+	iDevice->DrawingEnd();
+	}
+
+void CFbsBitGc::DoCopyRect(const TPoint& aOffset,const TRect& rect)
+	{
+	CFbsDrawDevice* drawDevice = iDevice->iDrawDevice;
+#ifdef _DEBUG
+	TRect deviceRect;
+	drawDevice->GetDrawRect(deviceRect);
+#endif
+	BG_ASSERT_DEBUG(rect.iTl.iX >= deviceRect.iTl.iX, EBitgdiPanicOutOfBounds);
+	BG_ASSERT_DEBUG(rect.iTl.iY >= deviceRect.iTl.iY, EBitgdiPanicOutOfBounds);
+	BG_ASSERT_DEBUG(rect.iBr.iX <= deviceRect.iBr.iX, EBitgdiPanicOutOfBounds);
+	BG_ASSERT_DEBUG(rect.iBr.iY <= deviceRect.iBr.iY, EBitgdiPanicOutOfBounds);
+
+	TRect offrect(rect);
+	offrect.Move(aOffset);
+
+	BG_ASSERT_DEBUG(offrect.iTl.iX >= deviceRect.iTl.iX, EBitgdiPanicOutOfBounds);
+	BG_ASSERT_DEBUG(offrect.iTl.iY >= deviceRect.iTl.iY, EBitgdiPanicOutOfBounds);
+	BG_ASSERT_DEBUG(offrect.iBr.iX <= deviceRect.iBr.iX, EBitgdiPanicOutOfBounds);
+	BG_ASSERT_DEBUG(offrect.iBr.iY <= deviceRect.iBr.iY, EBitgdiPanicOutOfBounds);
+
+	TInt y1 = rect.iTl.iY,y2 = rect.iBr.iY,yinc = 1; // default y2>y1
+	if (aOffset.iY > 0)	// y1>y2
+		{
+		y1 = rect.iBr.iY - 1;
+		y2 = rect.iTl.iY - 1;
+		yinc = -1;
+		}
+
+	const TInt width = rect.Width();
+	const TInt xoffset = rect.iTl.iX + aOffset.iX;
+	const TDisplayMode dispMode = ScanLineBufferDisplayMode(drawDevice);
+	TUint32* scanLineBuffer = drawDevice->ScanLineBuffer();
+
+	for (TInt row = y1; row != y2; row += yinc)
+		{
+		drawDevice->ReadLine(rect.iTl.iX,row,width,scanLineBuffer,dispMode);
+		drawDevice->WriteLine(xoffset,row + aOffset.iY,width, scanLineBuffer,iDrawMode);
+		}
+	}
+
+/**
+Draws and fills a rectangle.
+
+The function provides a concrete implementation of the pure virtual
+function <code>CGraphicsContext::DrawRect()</code>. The function
+behaviour is the same as documented in that class.
+*/
+EXPORT_C void CFbsBitGc::DrawRect(const TRect& aRect)
+	{
+	if (CheckDevice(aRect))
+		return;
+
+	TRect rcpy(aRect);
+	TRect clippedBoundingRect(rcpy);
+	clippedBoundingRect.Move(iOrigin);
+	clippedBoundingRect.Grow((iPenSize.iWidth >> 1) + 1,(iPenSize.iHeight >> 1) + 1);
+	if(!clippedBoundingRect.Intersects(iUserClipRect))
+		return;
+
+	CGraphicsAccelerator* ga = GraphicsAccelerator();
+
+	SetupDevice();
+	iDevice->DrawingBegin();
+	iBrushBitmap.BeginDataAccess();
+	CFbsRasterizer* brushRasterizer = PrepareRasterizerForExtendedBitmap(iBrushBitmap);
+
+	if (iPenSize.iWidth == 1 && iPenSize.iHeight == 1 && iPenStyle != ENullPen)
+		{
+		const TInt width = rcpy.Width();
+		const TInt height = rcpy.Height();
+		const TPoint currentLinePosition = iLinePosition;
+
+		if (iPenStyle != ESolidPen)
+			iDotParam = 0;
+
+		if (width)
+			DoDrawLine(rcpy.iTl,TPoint(rcpy.iBr.iX,rcpy.iTl.iY),ETrue); // top
+
+		if (height > 2 && width > 1)
+			DoDrawLine(TPoint(rcpy.iBr.iX-1,rcpy.iTl.iY+1),TPoint(rcpy.iBr.iX-1,rcpy.iBr.iY-1),ETrue); // right
+
+		if (width && height > 1)
+			DoDrawLine(TPoint(rcpy.iBr.iX-1,rcpy.iBr.iY-1),TPoint(rcpy.iTl.iX-1,rcpy.iBr.iY-1),ETrue); // bottom
+
+		if (height > 2)
+			DoDrawLine(TPoint(rcpy.iTl.iX,rcpy.iBr.iY-2),rcpy.iTl,ETrue); // left
+		
+		// Restore internal line position in case it has been modified by DoDrawLine().
+		// DrawRect() should not be modifying it.
+		iLinePosition = currentLinePosition;
+
+		if (width < 3 || height < 3)
+			goto nofill;
+
+		rcpy.Shrink(1,1);
+		rcpy.Move(iOrigin);
+		}
+	else if (iPenStyle != ENullPen && (iPenSize.iWidth >= 1 && iPenSize.iHeight >= 1))
+		{
+		rcpy.Move(iOrigin);
+
+		const TBrushStyle tempbrushstyle = iBrushStyle;
+		iBrushStyle = ESolidBrush;
+		const TRgb tempbrushColor = iBrushColor;
+		iBrushColor = iPenColor;
+		const CGraphicsContext::TDrawMode tempdrawmode = iDrawMode;
+
+		if(iDrawMode != CGraphicsContext::EDrawModeWriteAlpha)
+			{			
+			iDrawMode = CGraphicsContext::EDrawModePEN;
+			}
+
+		const TInt halfpenwidth = (iPenSize.iWidth - 1) >> 1;
+		const TInt halfpenheight = (iPenSize.iHeight - 1) >> 1;
+		const TInt otherhalfwidth = (iPenSize.iWidth >> 1) + 1;
+		const TInt otherhalfheight = (iPenSize.iHeight >> 1) + 1;
+
+		rcpy.iBr.iX--;
+		rcpy.iBr.iY--;
+
+		if (rcpy.iBr.iY - rcpy.iTl.iY <= iPenSize.iHeight + 1 || rcpy.iBr.iX - rcpy.iTl.iX <= iPenSize.iWidth + 1)
+			{
+			rcpy.iTl.iX -= halfpenwidth;
+			rcpy.iTl.iY -= halfpenheight;
+			rcpy.iBr.iX += otherhalfwidth;
+			rcpy.iBr.iY += otherhalfheight;
+
+			RectFill(rcpy);
+
+			iBrushStyle = tempbrushstyle;
+			iBrushColor = tempbrushColor;
+			iDrawMode = tempdrawmode;
+
+			goto nofill;
+			}
+		else
+			{
+			RectFill(TRect(rcpy.iTl.iX - halfpenwidth,rcpy.iTl.iY - halfpenheight,rcpy.iBr.iX + otherhalfwidth,rcpy.iTl.iY + otherhalfheight)); // top
+			RectFill(TRect(rcpy.iTl.iX - halfpenwidth,rcpy.iTl.iY + otherhalfheight,rcpy.iTl.iX + otherhalfwidth,rcpy.iBr.iY - halfpenheight)); // left
+			RectFill(TRect(rcpy.iBr.iX - halfpenwidth,rcpy.iTl.iY + otherhalfheight,rcpy.iBr.iX + otherhalfwidth,rcpy.iBr.iY - halfpenheight)); // right
+			RectFill(TRect(rcpy.iTl.iX - halfpenwidth,rcpy.iBr.iY - halfpenheight,rcpy.iBr.iX + otherhalfwidth,rcpy.iBr.iY + otherhalfheight)); // bottom
+
+			rcpy.iTl.iX += otherhalfwidth;
+			rcpy.iTl.iY += otherhalfheight;
+			rcpy.iBr.iX -= halfpenwidth;
+			rcpy.iBr.iY -= halfpenheight;
+
+			iBrushStyle = tempbrushstyle;
+			iBrushColor = tempbrushColor;
+			iDrawMode = tempdrawmode;
+			}
+		}
+	else
+		rcpy.Move(iOrigin);
+
+	//use Graphics accelerator if available
+	if(ga)
+		{
+		TInt i = -1;
+		//Draw rect
+		if(iPenStyle == ENullPen && iShadowMode == CFbsDrawDevice::ENoShadow)
+			{
+			if(iBrushStyle == ESolidBrush )
+				{
+				// EDrawModePEN and EDrawModeWriteAlpha mode should use the same method when
+				// (1) solid brush with opaque color is used. Or
+				// (2) solid brush with transparent color is used but display mode is
+				//     other than EColor64K, EColor16MU, EColor16MA, EColor16MAP.
+				//  in the same way as the software implemantation does and calls WriteRgbMulti method.
+				if(iDrawMode == EDrawModeWriteAlpha)
+					{
+					i = 0;
+					}
+				else if(iDrawMode == EDrawModePEN)
+					{
+					if(iBrushColor.Alpha() == 255)
+						{
+						i = 0;
+						}
+					else
+						{
+						TDisplayMode dispMode = iDevice->DisplayMode();
+						if(dispMode != EColor64K && dispMode != EColor16MU && dispMode != EColor16MA && dispMode != EColor16MAP)
+							{
+							i = 0;
+							}
+						}
+					}
+				//Invert color
+				else if(iDrawMode == EDrawModeNOTSCREEN)
+					{
+					i = 1;
+					}
+				}
+			//use a patter brush
+			else if(iBrushStyle == EPatternedBrush)
+				{
+				i = 2;
+				}
+			}
+
+		if(i != -1)
+			{
+	        TInt gaOperationResult = KErrUnknown;
+            iDevice->DrawingEnd();
+
+			const TInt limit=iDefaultRegionPtr->Count();
+			for (TInt count = 0; count < limit; count++)
+				{
+				iClipRect = (*iDefaultRegionPtr)[count];
+				if (!iClipRect.Intersects(rcpy))
+					continue;
+
+				iClipRect.Intersection(rcpy);
+				if (UserClipRect(iClipRect))
+					continue;
+
+				switch(i)
+					{
+				case 0:
+					gaOperationResult = ga->Operation(TGopFilledRect(iClipRect,iBrushColor));
+					break;
+				case 1:
+					gaOperationResult = ga->Operation(TGopInvertRect(iClipRect));
+					break;
+				case 2:
+					CFbsBitmap* brushbitmap = (CFbsBitmap*)&iBrushBitmap;
+					BG_ASSERT_ALWAYS(iBrushUsed,EBitgdiPanicInvalidBitmap);
+					BG_ASSERT_ALWAYS(brushbitmap != NULL,EBitgdiPanicInvalidBitmap);
+
+					TAcceleratedBitmapSpec brushBitmapSpec(brushbitmap);
+					TGopFillPattern gopFillPattern;
+					gopFillPattern.iBitmap = brushBitmapSpec;
+					gopFillPattern.iOrigin = iBrushOrigin;
+					gaOperationResult = ga->Operation(TGopFilledRectWithPattern(iClipRect,gopFillPattern));
+					break;
+					}			
+				if(gaOperationResult != KErrNone)
+					break;
+				}
+			if(gaOperationResult == KErrNone)
+				goto finish;
+			iDevice->DrawingBegin();
+			}
+		}
+
+	RectFill(rcpy);
+
+nofill:
+	iDevice->DrawingEnd();
+finish:
+	if (brushRasterizer)
+		{
+		brushRasterizer->EndBitmap(iBrushBitmap.SerialNumber());
+		}
+	iBrushBitmap.EndDataAccess(ETrue);
+	}
+
+// if iBrushBitmap is an extended bitmap, PrepareRasterizerForExtendedBitmap() must have been called before this method
+void CFbsBitGc::RectFill(const TRect& aRect)
+	{
+	if (aRect.IsEmpty() || iBrushStyle == ENullBrush)
+		return;
+
+	CFbsDrawDevice* drawDevice = iDevice->iDrawDevice;
+
+	AddRect(aRect);
+
+	const TPoint origin = iOrigin + iBrushOrigin;
+
+	const TInt limit=iDefaultRegionPtr->Count();
+	for (TInt count = 0; count < limit; count++)
+		{
+		iClipRect = (*iDefaultRegionPtr)[count];
+		if (!iClipRect.Intersects(aRect))
+			continue;
+
+		iClipRect.Intersection(aRect);
+		if (UserClipRect(iClipRect))
+			continue;
+
+#ifdef _DEBUG
+		TRect deviceRect;
+		drawDevice->GetDrawRect(deviceRect);
+#endif
+		BG_ASSERT_DEBUG(iClipRect.iTl.iX >= deviceRect.iTl.iX, EBitgdiPanicOutOfBounds);
+		BG_ASSERT_DEBUG(iClipRect.iTl.iY >= deviceRect.iTl.iY, EBitgdiPanicOutOfBounds);
+		BG_ASSERT_DEBUG(iClipRect.iBr.iX <= deviceRect.iBr.iX, EBitgdiPanicOutOfBounds);
+		BG_ASSERT_DEBUG(iClipRect.iBr.iY <= deviceRect.iBr.iY, EBitgdiPanicOutOfBounds);
+
+		TInt xcoord = iClipRect.iTl.iX;
+		TInt ycoord = iClipRect.iTl.iY;
+
+
+		switch(iBrushStyle)
+			{
+		case ESolidBrush:
+			drawDevice->WriteRgbMulti(iClipRect.iTl.iX,iClipRect.iTl.iY,
+					iClipRect.Width(),iClipRect.Height(),iBrushColor,iDrawMode);
+			break;
+		case EPatternedBrush:
+			{
+			CBitwiseBitmap* brushbitmap = iBrushBitmap.Address();
+			BG_ASSERT_ALWAYS(iBrushUsed,EBitgdiPanicInvalidBitmap);
+			BG_ASSERT_ALWAYS(brushbitmap != NULL,EBitgdiPanicInvalidBitmap);
+
+			TRect sourcerect(iClipRect);
+			sourcerect.Move(-origin);
+			DoBitBlt(iClipRect.iTl,brushbitmap,iBrushBitmap.DataAddress(),iBrushBitmap.DataStride(),sourcerect);
+			break;
+			}
+		case EHorizontalHatchBrush:
+			drawDevice->WriteRgbMulti(iClipRect.iTl.iX,iClipRect.iTl.iY,
+					iClipRect.Width(),iClipRect.Height(),iBrushColor,iDrawMode);
+			while (Abs((ycoord - origin.iY) % 3) != 2)
+				ycoord++;
+			for (; ycoord < iClipRect.iBr.iY; ycoord += 3)
+				drawDevice->WriteRgbMulti(iClipRect.iTl.iX,ycoord,iClipRect.Width(),1,iPenColor,iDrawMode);
+			break;
+		case EVerticalHatchBrush:
+			drawDevice->WriteRgbMulti(iClipRect.iTl.iX,iClipRect.iTl.iY,
+					iClipRect.Width(),iClipRect.Height(),iBrushColor,iDrawMode);
+			while (Abs((xcoord - origin.iX) % 3) != 2)
+				xcoord++;
+			for (; xcoord < iClipRect.iBr.iX; xcoord += 3)
+				drawDevice->WriteRgbMulti(xcoord,iClipRect.iTl.iY,1,iClipRect.Height(),iPenColor,iDrawMode);
+			break;
+		case ESquareCrossHatchBrush:
+			drawDevice->WriteRgbMulti(iClipRect.iTl.iX,iClipRect.iTl.iY,
+					iClipRect.Width(),iClipRect.Height(),iBrushColor,iDrawMode);
+			while (Abs((ycoord - origin.iY) % 3) != 2)
+				ycoord++;
+			for (; ycoord < iClipRect.iBr.iY; ycoord += 3) // horizontal lines
+				drawDevice->WriteRgbMulti(iClipRect.iTl.iX,ycoord,iClipRect.Width(),1,iPenColor,iDrawMode);
+
+			ycoord = iClipRect.iTl.iY;
+			while (Abs((ycoord - origin.iY) % 3) != 2 && ycoord < iClipRect.iBr.iY) // above the top horizontal line
+				{
+				xcoord = iClipRect.iTl.iX;
+				while (Abs((xcoord - origin.iX) % 3) != 2)
+					xcoord++;
+				for (; xcoord < iClipRect.iBr.iX; xcoord += 3)
+					drawDevice->WriteRgb(xcoord,ycoord,iPenColor,iDrawMode);
+				ycoord++;
+				}
+
+			ycoord += 3;
+			for (; ycoord < iClipRect.iBr.iY; ycoord += 3) // between the top and bottom horizontals
+				{
+				xcoord = iClipRect.iTl.iX;
+				while (Abs((xcoord - origin.iX) % 3) != 2)
+					xcoord++;
+				for (; xcoord < iClipRect.iBr.iX; xcoord += 3)
+					drawDevice->WriteRgbMulti(xcoord,ycoord - 2,1,2,iPenColor,iDrawMode);
+				}
+
+			ycoord -= 3;
+			while (ycoord < iClipRect.iBr.iY) // below the bottom horizontal
+				{
+				xcoord = iClipRect.iTl.iX;
+				while (Abs((xcoord - origin.iX) % 3) != 2)
+					xcoord++;
+				for (; xcoord < iClipRect.iBr.iX; xcoord += 3)
+					drawDevice->WriteRgb(xcoord,ycoord,iPenColor,iDrawMode);
+				ycoord++;
+				}
+			break;
+		case EForwardDiagonalHatchBrush:
+			drawDevice->WriteRgbMulti(iClipRect.iTl.iX,iClipRect.iTl.iY,
+					iClipRect.Width(),iClipRect.Height(),iBrushColor,iDrawMode);
+			for (; ycoord < iClipRect.iBr.iY; ycoord++)
+				{
+				xcoord = iClipRect.iTl.iX;
+				TInt diff = (origin.iX + origin.iY - xcoord - ycoord) % 3;
+				if (diff < 0)
+					diff += 3;
+				xcoord += diff;
+				for (; xcoord < iClipRect.iBr.iX; xcoord += 3)
+					drawDevice->WriteRgb(xcoord,ycoord,iPenColor,iDrawMode);
+				}
+			break;
+		case ERearwardDiagonalHatchBrush:
+			drawDevice->WriteRgbMulti(iClipRect.iTl.iX,iClipRect.iTl.iY,
+					iClipRect.Width(),iClipRect.Height(),iBrushColor,iDrawMode);
+			for (; ycoord < iClipRect.iBr.iY; ycoord++)
+				{
+				xcoord = iClipRect.iTl.iX;
+				TInt diff = (origin.iX - origin.iY - xcoord + ycoord) % 3;
+				if (diff < 0)
+					diff += 3;
+				xcoord += diff;
+				for (; xcoord < iClipRect.iBr.iX; xcoord += 3)
+					drawDevice->WriteRgb(xcoord,ycoord,iPenColor,iDrawMode);
+				}
+			break;
+		case EDiamondCrossHatchBrush:
+			{
+			drawDevice->WriteRgbMulti(iClipRect.iTl.iX,iClipRect.iTl.iY,
+					iClipRect.Width(),iClipRect.Height(),iBrushColor,iDrawMode);
+			TInt sum = xcoord + ycoord - origin.iX - origin.iY;
+			for (; ycoord < iClipRect.iBr.iY; ycoord++,sum++)
+				{
+				TInt currentsum = sum;
+				for (xcoord = iClipRect.iTl.iX; xcoord < iClipRect.iBr.iX; xcoord++,currentsum++)
+					{
+					if((currentsum & 1) == 0 && ((currentsum & 3) != 0 || ((xcoord-origin.iX) & 1) == 1))
+						drawDevice->WriteRgb(xcoord,ycoord,iPenColor,iDrawMode);
+					}
+				}
+			break;
+			}
+		default:
+			return;
+			}
+
+		drawDevice->UpdateRegion(iClipRect);
+		}
+	}
+