sl@0: // Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
sl@0: // All rights reserved.
sl@0: // This component and the accompanying materials are made available
sl@0: // under the terms of "Eclipse Public License v1.0"
sl@0: // which accompanies this distribution, and is available
sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html".
sl@0: //
sl@0: // Initial Contributors:
sl@0: // Nokia Corporation - initial contribution.
sl@0: //
sl@0: // Contributors:
sl@0: //
sl@0: // Description:
sl@0: //
sl@0: 
sl@0: #include "directgdiadapter.h"
sl@0: #include "swdirectgdiengine.h"
sl@0: 
sl@0: /** 
sl@0: @see MDirectGdiEngine::CopyRect()
sl@0: */
sl@0: void CSwDirectGdiEngine::CopyRect(const TPoint& aOffset, const TRect& aRect)
sl@0: 	{	
sl@0: 	TRect deviceRect;
sl@0: 	iDrawDevice->GetDrawRect(deviceRect);
sl@0: 	const TPoint back(TPoint(0,0) - aOffset);
sl@0: 	TRect rcpy(aRect);
sl@0: 	rcpy.Move(iOrigin);
sl@0: 	rcpy.Intersection(deviceRect);
sl@0: 	((TRegion*)iDefaultRegionPtr)->Sort(aOffset);
sl@0: 	
sl@0: 	TRect targetRect(rcpy);
sl@0: 	targetRect.Move(aOffset);
sl@0: 	targetRect.BoundingRect(rcpy);
sl@0: 	
sl@0: 	TRect clipRect(0,0,0,0);
sl@0: 	const TInt limit = iDefaultRegionPtr->Count();
sl@0: 	for(TInt count = 0; count < limit; count++)
sl@0: 		{
sl@0: 		clipRect = (*iDefaultRegionPtr)[count];
sl@0: 		
sl@0: 		clipRect.Move(back);
sl@0: 		if (!clipRect.Intersects(rcpy))
sl@0: 			{
sl@0: 			continue;
sl@0: 			}
sl@0: 		
sl@0: 		clipRect.Intersection(rcpy);
sl@0: 		DirectGdi::TDrawMode drawMode = iDrawMode;
sl@0: 		iDrawMode = DirectGdi::EDrawModeWriteAlpha;
sl@0: 		DoCopyRect(aOffset, clipRect);
sl@0: 		iDrawMode = drawMode; // restore the previous draw mode
sl@0: 		clipRect.Move(aOffset);
sl@0: 		iDrawDevice->UpdateRegion(clipRect);
sl@0: 		}
sl@0: 	}
sl@0: 
sl@0: /**
sl@0: @see CopyRect()
sl@0: @panic DGDIAdapter 1013, if aRect or aOffset are outside of the destination bounds (debug only).
sl@0:  */ 
sl@0: void CSwDirectGdiEngine::DoCopyRect(const TPoint& aOffset, const TRect& aRect)
sl@0: 	{
sl@0: #ifdef _DEBUG
sl@0: 	TRect deviceRect;
sl@0: 	iDrawDevice->GetDrawRect(deviceRect);
sl@0: #endif
sl@0: 	GRAPHICS_ASSERT_DEBUG(aRect.iTl.iX >= deviceRect.iTl.iX, EDirectGdiPanicOutOfBounds);
sl@0: 	GRAPHICS_ASSERT_DEBUG(aRect.iTl.iY >= deviceRect.iTl.iY, EDirectGdiPanicOutOfBounds);
sl@0: 	GRAPHICS_ASSERT_DEBUG(aRect.iBr.iX <= deviceRect.iBr.iX, EDirectGdiPanicOutOfBounds);
sl@0: 	GRAPHICS_ASSERT_DEBUG(aRect.iBr.iY <= deviceRect.iBr.iY, EDirectGdiPanicOutOfBounds);
sl@0: 
sl@0: 	TRect offsetRect(aRect);
sl@0: 	offsetRect.Move(aOffset);
sl@0: 
sl@0: 	GRAPHICS_ASSERT_DEBUG(offsetRect.iTl.iX >= deviceRect.iTl.iX, EDirectGdiPanicOutOfBounds);
sl@0: 	GRAPHICS_ASSERT_DEBUG(offsetRect.iTl.iY >= deviceRect.iTl.iY, EDirectGdiPanicOutOfBounds);
sl@0: 	GRAPHICS_ASSERT_DEBUG(offsetRect.iBr.iX <= deviceRect.iBr.iX, EDirectGdiPanicOutOfBounds);
sl@0: 	GRAPHICS_ASSERT_DEBUG(offsetRect.iBr.iY <= deviceRect.iBr.iY, EDirectGdiPanicOutOfBounds);
sl@0: 
sl@0: 	TInt y1 = aRect.iTl.iY;
sl@0: 	TInt y2 = aRect.iBr.iY; 
sl@0: 	TInt yinc = 1; // default y2>y1
sl@0: 	if (aOffset.iY > 0)	// y1>y2
sl@0: 		{
sl@0: 		y1 = aRect.iBr.iY - 1;
sl@0: 		y2 = aRect.iTl.iY - 1;
sl@0: 		yinc = -1;
sl@0: 		}
sl@0: 
sl@0: 	const TInt width = aRect.Width();
sl@0: 	const TInt xoffset = aRect.iTl.iX + aOffset.iX;
sl@0: 	const TDisplayMode dispMode = ScanLineBufferDisplayMode(iDrawDevice);
sl@0: 	TUint32* scanLineBuffer = iDrawDevice->ScanLineBuffer();
sl@0: 
sl@0: 	for (TInt row = y1; row != y2; row += yinc)
sl@0: 		{
sl@0: 		iDrawDevice->ReadLine(aRect.iTl.iX, row, width, scanLineBuffer, dispMode);
sl@0: 		iDrawDevice->WriteLine(xoffset, row + aOffset.iY, width, scanLineBuffer, GcDrawMode(iDrawMode));
sl@0: 		}
sl@0: 	}
sl@0: 
sl@0: /** 
sl@0: @see MDirectGdiEngine::DrawRect()
sl@0: */
sl@0: void CSwDirectGdiEngine::DrawRect(const TRect& aRect)
sl@0: 	{
sl@0: 	TRect rcpy(aRect);
sl@0: 
sl@0: 	iBrushBitmap.BeginDataAccess();
sl@0: 	
sl@0: 	if ((iPenSize.iWidth == 1) && (iPenSize.iHeight == 1) && iPenStyle != DirectGdi::ENullPen)
sl@0: 		{
sl@0: 		const TInt width = rcpy.Width();
sl@0: 		const TInt height = rcpy.Height();
sl@0: 		const TPoint currentLinePosition = iLinePosition;
sl@0: 
sl@0: 		if (iPenStyle != DirectGdi::ESolidPen)
sl@0: 			{
sl@0: 			iDotParam = 0;
sl@0: 			}
sl@0: 
sl@0: 		DoDrawLine(rcpy.iTl,TPoint(rcpy.iBr.iX,rcpy.iTl.iY),ETrue); // top
sl@0: 
sl@0: 		if (height > 2 && width > 1)
sl@0: 			{
sl@0: 			DoDrawLine(TPoint(rcpy.iBr.iX-1,rcpy.iTl.iY+1),TPoint(rcpy.iBr.iX-1,rcpy.iBr.iY-1),ETrue); // right
sl@0: 			}
sl@0: 
sl@0: 		if (height > 1)
sl@0: 			{
sl@0: 			DoDrawLine(TPoint(rcpy.iBr.iX-1,rcpy.iBr.iY-1),TPoint(rcpy.iTl.iX-1,rcpy.iBr.iY-1),ETrue); // bottom
sl@0: 			}
sl@0: 
sl@0: 		if (height > 2)
sl@0: 			{
sl@0: 			DoDrawLine(TPoint(rcpy.iTl.iX,rcpy.iBr.iY-2),rcpy.iTl,ETrue); // left
sl@0: 			}
sl@0: 		
sl@0: 		// Restore internal line position in case it has been modified by DoDrawLine().
sl@0: 		// DrawRect() should not be modifying it.
sl@0: 		iLinePosition = currentLinePosition;
sl@0: 
sl@0: 		if (width < 3 || height < 3)
sl@0: 			{
sl@0: 			goto nofill;
sl@0: 			}
sl@0: 
sl@0: 		rcpy.Shrink(1,1);
sl@0: 		rcpy.Move(iOrigin);
sl@0: 		}
sl@0: 	else if ((iPenStyle != DirectGdi::ENullPen) && (iPenSize.iWidth >= 1 && iPenSize.iHeight >= 1))
sl@0: 		{
sl@0: 		rcpy.Move(iOrigin);
sl@0: 
sl@0: 		const DirectGdi::TBrushStyle tempbrushstyle = iBrushStyle;
sl@0: 		const TRgb tempbrushColor = iBrushColor;
sl@0: 		const DirectGdi::TDrawMode tempdrawmode = iDrawMode;
sl@0: 				
sl@0: 		const TInt halfpenwidth = (iPenSize.iWidth - 1) >> 1;
sl@0: 		const TInt halfpenheight = (iPenSize.iHeight - 1) >> 1;
sl@0: 		const TInt otherhalfwidth = (iPenSize.iWidth >> 1) + 1;
sl@0: 		const TInt otherhalfheight = (iPenSize.iHeight >> 1) + 1;
sl@0: 
sl@0: 		rcpy.iBr.iX--;
sl@0: 		rcpy.iBr.iY--;
sl@0: 
sl@0: 		if (((rcpy.iBr.iY - rcpy.iTl.iY) <= (iPenSize.iHeight + 1)) || ((rcpy.iBr.iX - rcpy.iTl.iX) <= (iPenSize.iWidth + 1)))
sl@0: 			{
sl@0: 			iBrushColor = iPenColor;
sl@0: 			iBrushStyle = DirectGdi::ESolidBrush;
sl@0: 			if(iDrawMode != DirectGdi::EDrawModeWriteAlpha)
sl@0: 				{			
sl@0: 				iDrawMode = DirectGdi::EDrawModePEN;
sl@0: 				}
sl@0: 						
sl@0: 			rcpy.iTl.iX -= halfpenwidth;
sl@0: 			rcpy.iTl.iY -= halfpenheight;
sl@0: 			rcpy.iBr.iX += otherhalfwidth;
sl@0: 			rcpy.iBr.iY += otherhalfheight;			
sl@0: 			RectFill(rcpy);
sl@0: 			}
sl@0: 		else
sl@0: 			{
sl@0: 			// In the event the pen outline is semi-transparent, we must do the fill first so that the
sl@0: 			// outline is blended over the top.
sl@0: 			RectFill(rcpy);
sl@0: 			
sl@0: 			iBrushColor = iPenColor;
sl@0: 			iBrushStyle = DirectGdi::ESolidBrush;
sl@0: 			if(iDrawMode != DirectGdi::EDrawModeWriteAlpha)
sl@0: 				{			
sl@0: 				iDrawMode = DirectGdi::EDrawModePEN;
sl@0: 				}
sl@0: 			RectFill(TRect(rcpy.iTl.iX - halfpenwidth,rcpy.iTl.iY - halfpenheight,rcpy.iBr.iX + otherhalfwidth,rcpy.iTl.iY + otherhalfheight)); // top
sl@0: 			RectFill(TRect(rcpy.iTl.iX - halfpenwidth,rcpy.iTl.iY + otherhalfheight,rcpy.iTl.iX + otherhalfwidth,rcpy.iBr.iY - halfpenheight)); // left
sl@0: 			RectFill(TRect(rcpy.iBr.iX - halfpenwidth,rcpy.iTl.iY + otherhalfheight,rcpy.iBr.iX + otherhalfwidth,rcpy.iBr.iY - halfpenheight)); // right
sl@0: 			RectFill(TRect(rcpy.iTl.iX - halfpenwidth,rcpy.iBr.iY - halfpenheight,rcpy.iBr.iX + otherhalfwidth,rcpy.iBr.iY + otherhalfheight)); // bottom
sl@0: 			}
sl@0: 		
sl@0: 		iBrushStyle = tempbrushstyle;
sl@0: 		iBrushColor = tempbrushColor;
sl@0: 		iDrawMode = tempdrawmode;
sl@0: 		goto nofill;
sl@0: 		}
sl@0: 	else
sl@0: 		{
sl@0: 		rcpy.Move(iOrigin);
sl@0: 		}
sl@0: 
sl@0: 	RectFill(rcpy);
sl@0: 
sl@0: nofill:
sl@0: 	iBrushBitmap.EndDataAccess(ETrue);
sl@0: 	}
sl@0: 
sl@0: /**
sl@0: Fills the given area using the current brush.
sl@0: 
sl@0: @param aRect The area to fill.
sl@0: @panic DGDIAdapter 1013, if the a clipping rectangle is fully outside of the destination bounds (debug only).
sl@0: @panic DGDIAdapter 7, if using EPatternedBrush with no brush pattern bitmap.
sl@0:  */ 
sl@0: void CSwDirectGdiEngine::RectFill(const TRect& aRect)
sl@0: 	{	
sl@0: 	if (aRect.IsEmpty() || iBrushStyle == DirectGdi::ENullBrush)
sl@0: 		{
sl@0: 		return;
sl@0: 		}
sl@0: 	
sl@0: 	const TPoint origin = iOrigin + iBrushOrigin;
sl@0: 	const TInt limit = iDefaultRegionPtr->Count();
sl@0: 	TRect clipRect(0,0,0,0);
sl@0: 	for (TInt count = 0; count < limit; count++)
sl@0: 		{
sl@0: 		clipRect = (*iDefaultRegionPtr)[count];
sl@0: 		if (!clipRect.Intersects(aRect))
sl@0: 			{
sl@0: 			continue;
sl@0: 			}
sl@0: 		
sl@0: 		clipRect.Intersection(aRect);	
sl@0: 		
sl@0: #ifdef _DEBUG
sl@0: 		TRect deviceRect;
sl@0: 		iDrawDevice->GetDrawRect(deviceRect);
sl@0: 		GRAPHICS_ASSERT_DEBUG(clipRect.iTl.iX >= deviceRect.iTl.iX, EDirectGdiPanicOutOfBounds);
sl@0: 		GRAPHICS_ASSERT_DEBUG(clipRect.iTl.iY >= deviceRect.iTl.iY, EDirectGdiPanicOutOfBounds);
sl@0: 		GRAPHICS_ASSERT_DEBUG(clipRect.iBr.iX <= deviceRect.iBr.iX, EDirectGdiPanicOutOfBounds);
sl@0: 		GRAPHICS_ASSERT_DEBUG(clipRect.iBr.iY <= deviceRect.iBr.iY, EDirectGdiPanicOutOfBounds);
sl@0: #endif
sl@0: 
sl@0: 		TInt xcoord = clipRect.iTl.iX;
sl@0: 		TInt ycoord = clipRect.iTl.iY;
sl@0: 		const CGraphicsContext::TDrawMode drawMode = GcDrawMode(iDrawMode);
sl@0: 		
sl@0: 		switch(iBrushStyle)
sl@0: 		{
sl@0: 		case DirectGdi::ESolidBrush:
sl@0: 			iDrawDevice->WriteRgbMulti(clipRect.iTl.iX,clipRect.iTl.iY,
sl@0: 							clipRect.Width(),clipRect.Height(),iBrushColor,drawMode);
sl@0: 			break;
sl@0: 		case DirectGdi::EPatternedBrush:
sl@0: 			{
sl@0: 			iBrushBitmap.BeginDataAccess();
sl@0: 			CBitwiseBitmap* brushbitmap = iBrushBitmap.Address();
sl@0: 			
sl@0: 			GRAPHICS_ASSERT_ALWAYS(brushbitmap != NULL, EDirectGdiPanicInvalidBitmap);
sl@0: 			
sl@0: 			TRect sourcerect(clipRect);
sl@0: 			sourcerect.Move(-origin);
sl@0: 						
sl@0: 			DoBitBlt(clipRect.iTl,brushbitmap,iBrushBitmap.DataAddress(),iBrushBitmap.DataStride(),sourcerect);
sl@0: 			iBrushBitmap.EndDataAccess(ETrue);
sl@0: 			break;
sl@0: 			}
sl@0: 		case DirectGdi::EHorizontalHatchBrush:
sl@0: 			iDrawDevice->WriteRgbMulti(clipRect.iTl.iX,clipRect.iTl.iY,
sl@0: 					clipRect.Width(),clipRect.Height(),iBrushColor,drawMode);
sl@0: 			while (Abs((ycoord - origin.iY) % 3) != 2)
sl@0: 				{
sl@0: 				ycoord++;
sl@0: 				}
sl@0: 			for (; ycoord < clipRect.iBr.iY; ycoord += 3)
sl@0: 				{
sl@0: 				iDrawDevice->WriteRgbMulti(clipRect.iTl.iX,ycoord,clipRect.Width(),1,iPenColor,drawMode);
sl@0: 				}
sl@0: 				break;
sl@0: 			case DirectGdi::EVerticalHatchBrush:
sl@0: 				iDrawDevice->WriteRgbMulti(clipRect.iTl.iX,clipRect.iTl.iY,
sl@0: 						clipRect.Width(),clipRect.Height(),iBrushColor,drawMode);
sl@0: 				while (Abs((xcoord - origin.iX) % 3) != 2)
sl@0: 					{
sl@0: 					xcoord++;
sl@0: 					}
sl@0: 				for (; xcoord < clipRect.iBr.iX; xcoord += 3)
sl@0: 					{
sl@0: 					iDrawDevice->WriteRgbMulti(xcoord,clipRect.iTl.iY,1,clipRect.Height(),iPenColor,drawMode);
sl@0: 					}
sl@0: 				break;
sl@0: 			case DirectGdi::ESquareCrossHatchBrush:
sl@0: 				iDrawDevice->WriteRgbMulti(clipRect.iTl.iX,clipRect.iTl.iY,
sl@0: 						clipRect.Width(),clipRect.Height(),iBrushColor,drawMode);
sl@0: 				while (Abs((ycoord - origin.iY) % 3) != 2)
sl@0: 					{
sl@0: 					ycoord++;
sl@0: 					}
sl@0: 				for (; ycoord < clipRect.iBr.iY; ycoord += 3) // horizontal lines
sl@0: 					{
sl@0: 					iDrawDevice->WriteRgbMulti(clipRect.iTl.iX,ycoord,clipRect.Width(),1,iPenColor,drawMode);
sl@0: 					}
sl@0: 
sl@0: 				ycoord = clipRect.iTl.iY;
sl@0: 				while (Abs((ycoord - origin.iY) % 3) != 2 && ycoord < clipRect.iBr.iY) // above the top horizontal line
sl@0: 					{
sl@0: 					xcoord = clipRect.iTl.iX;
sl@0: 					while (Abs((xcoord - origin.iX) % 3) != 2)
sl@0: 						{
sl@0: 						xcoord++;
sl@0: 						}
sl@0: 					for (; xcoord < clipRect.iBr.iX; xcoord += 3)
sl@0: 						{
sl@0: 						iDrawDevice->WriteRgb(xcoord,ycoord,iPenColor,drawMode);
sl@0: 						}
sl@0: 					ycoord++;
sl@0: 					}
sl@0: 				ycoord += 3;
sl@0: 				for (; ycoord < clipRect.iBr.iY; ycoord += 3) // between the top and bottom horizontals
sl@0: 					{
sl@0: 					xcoord = clipRect.iTl.iX;
sl@0: 					while (Abs((xcoord - origin.iX) % 3) != 2)
sl@0: 						{
sl@0: 						xcoord++;
sl@0: 						}
sl@0: 					for (; xcoord < clipRect.iBr.iX; xcoord += 3)
sl@0: 						{
sl@0: 						iDrawDevice->WriteRgbMulti(xcoord,ycoord - 2,1,2,iPenColor,drawMode);
sl@0: 						}
sl@0: 					}
sl@0: 
sl@0: 				ycoord -= 3;
sl@0: 				while (ycoord < clipRect.iBr.iY) // below the bottom horizontal
sl@0: 					{
sl@0: 					xcoord = clipRect.iTl.iX;
sl@0: 					while (Abs((xcoord - origin.iX) % 3) != 2)
sl@0: 						{
sl@0: 						xcoord++;
sl@0: 						}
sl@0: 					for (; xcoord < clipRect.iBr.iX; xcoord += 3)
sl@0: 						{
sl@0: 						iDrawDevice->WriteRgb(xcoord,ycoord,iPenColor,drawMode);
sl@0: 						}
sl@0: 					ycoord++;
sl@0: 					}
sl@0: 				break;
sl@0: 			case DirectGdi::EForwardDiagonalHatchBrush:
sl@0: 				iDrawDevice->WriteRgbMulti(clipRect.iTl.iX,clipRect.iTl.iY,
sl@0: 						clipRect.Width(),clipRect.Height(),iBrushColor,drawMode);
sl@0: 				for (; ycoord < clipRect.iBr.iY; ycoord++)
sl@0: 					{
sl@0: 					xcoord = clipRect.iTl.iX;
sl@0: 					TInt diff = (origin.iX + origin.iY - xcoord - ycoord) % 3;
sl@0: 					if (diff < 0)
sl@0: 						{
sl@0: 						diff += 3;
sl@0: 						}
sl@0: 					xcoord += diff;
sl@0: 					for (; xcoord < clipRect.iBr.iX; xcoord += 3)
sl@0: 						{
sl@0: 						iDrawDevice->WriteRgb(xcoord,ycoord,iPenColor,drawMode);
sl@0: 						}
sl@0: 					}
sl@0: 				break;
sl@0: 			case DirectGdi::ERearwardDiagonalHatchBrush:
sl@0: 				iDrawDevice->WriteRgbMulti(clipRect.iTl.iX,clipRect.iTl.iY,
sl@0: 						clipRect.Width(),clipRect.Height(),iBrushColor,drawMode);
sl@0: 				for (; ycoord < clipRect.iBr.iY; ycoord++)
sl@0: 					{
sl@0: 					xcoord = clipRect.iTl.iX;
sl@0: 					TInt diff = (origin.iX - origin.iY - xcoord + ycoord) % 3;
sl@0: 					if (diff < 0)
sl@0: 						{
sl@0: 						diff += 3;
sl@0: 						}
sl@0: 					xcoord += diff;
sl@0: 					for (; xcoord < clipRect.iBr.iX; xcoord += 3)
sl@0: 						{
sl@0: 						iDrawDevice->WriteRgb(xcoord,ycoord,iPenColor,drawMode);
sl@0: 						}
sl@0: 					}
sl@0: 				break;
sl@0: 			case DirectGdi::EDiamondCrossHatchBrush:
sl@0: 				{
sl@0: 				iDrawDevice->WriteRgbMulti(clipRect.iTl.iX,clipRect.iTl.iY,
sl@0: 						clipRect.Width(),clipRect.Height(),iBrushColor,drawMode);
sl@0: 				TInt sum = xcoord + ycoord - origin.iX - origin.iY;
sl@0: 				for (; ycoord < clipRect.iBr.iY; ycoord++,sum++)
sl@0: 					{
sl@0: 					TInt currentsum = sum;
sl@0: 					for (xcoord = clipRect.iTl.iX; xcoord < clipRect.iBr.iX; xcoord++,currentsum++)
sl@0: 						{
sl@0: 						if((currentsum & 1) == 0 && ((currentsum & 3) != 0 || ((xcoord-origin.iX) & 1) == 1))
sl@0: 							{
sl@0: 							iDrawDevice->WriteRgb(xcoord,ycoord,iPenColor,drawMode);
sl@0: 							}
sl@0: 						}
sl@0: 					}
sl@0: 				break;
sl@0: 				}
sl@0: 			default:
sl@0: 				return;
sl@0: 				}
sl@0: 
sl@0: 			iDrawDevice->UpdateRegion(clipRect);
sl@0: 			}		
sl@0: 	}