graphicsdeviceinterface/screendriver/sbit/BMDRAW24U.CPP
author Faisal Memon <faisal.memon@nokia.com>
Fri, 25 Jun 2010 17:49:58 +0100
branchEGL_MERGE
changeset 105 158b2308cc08
parent 0 5d03bc08d59c
child 33 25f95128741d
permissions -rw-r--r--
Fix def files so that the implementation agnostic interface definition has no non-standards defined entry points, and change the eglrefimpl specific implementation to place its private entry points high up in the ordinal order space in the implementation region, not the standards based entrypoints region.

// Copyright (c) 2003-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 "BMDRAW.H"
#include "BitDrawInterfaceId.h"
#include <graphics/lookuptable.h>

TInt CDrawUTwentyFourBppBitmap::Construct(TSize aSize)
	{
	return Construct(aSize, aSize.iWidth << 2);
	}

TInt CDrawUTwentyFourBppBitmap::Construct(TSize aSize, TInt aStride)
	{
	iDispMode = EColor16MU;
	return CDrawThirtyTwoBppBitmapCommon::Construct(aSize, aStride);
	}

/**
MAlphaBlend::WriteRgbAlphaLine() implementation.
@see MAlphaBlend::WriteRgbAlphaLine()
*/
void CDrawUTwentyFourBppBitmap::WriteRgbAlphaLine(TInt aX, TInt aY, TInt aLength,
													const TUint8* aRgbBuffer,
													const TUint8* aMaskBuffer,
													MAlphaBlend::TShadowing aShadowing,
													CGraphicsContext::TDrawMode /*aDrawMode*/)
	{
	// precondition for this function is that the aRgbBuffer lies on a word boundary
    // Assert checks that the pointer is at a word boundary
    __ASSERT_DEBUG(!(((TUint)aRgbBuffer) & 0x3), Panic(EScreenDriverPanicInvalidPointer));
    
	DeOrientate(aX,aY);
	TUint32* pixelPtr = PixelAddress(aX,aY);
	TUint32* rgbBuffer = (TUint32*)aRgbBuffer;
	const TInt pixelPtrInc = PixelAddressIncrement();
	const TUint8* maskBufferPtrLimit = aMaskBuffer + aLength;
	
	if (!(iShadowMode & (EFade | EShadow)) && (iUserDispMode == ENone))
		{
		while (aMaskBuffer < maskBufferPtrLimit)
			{
			*pixelPtr = CalcAlphaPixel(*rgbBuffer, *aMaskBuffer, *pixelPtr);
			aMaskBuffer++;
			pixelPtr += pixelPtrInc;
			rgbBuffer++;
			}
		}
	else
		{
		while (aMaskBuffer < maskBufferPtrLimit)
			{
			TInt mask = *aMaskBuffer++;
			if (mask)
				{     
				TInt b = aRgbBuffer[0];
				TInt g = aRgbBuffer[1];
				TInt r = aRgbBuffer[2];
				if(aShadowing == MAlphaBlend::EShdwBefore)
					{
					if (iShadowMode & EFade)
						{
						r = ((r * iFadeMapFactor) >> 8) + iFadeMapOffset;
						g = ((g * iFadeMapFactor) >> 8) + iFadeMapOffset;
						b = ((b * iFadeMapFactor) >> 8) + iFadeMapOffset;
						}
					if (iShadowMode & EShadow)
						{
						r = (Max(0,r-0x40));
						g = (Max(0,g-0x40));
						b = (Max(0,b-0x40));
						}
					}
				if (mask != 0xff)
					{
					// (mask * r + (255 - mask) * value) / 255 =
					// ((257 * mask * (r - value)) >> 16) + value
					TInt value = *pixelPtr & 0xffffff;
					mask = (mask << 8) + mask; // mask = mask * 257
					TInt v = value >> 16;
					r = ((mask * (r - v)) >> 16) + v;
					v = (value >> 8) & 0xff;
					g = ((mask * (g - v)) >> 16) + v;
					v = value & 0xff;
					b = ((mask * (b - v)) >> 16) + v;
					}
				if(aShadowing == MAlphaBlend::EShdwAfter)
					{
					if (iShadowMode & EFade)
						{  
						r = ((r * iFadeMapFactor) >> 8) + iFadeMapOffset;
						g = ((g * iFadeMapFactor) >> 8) + iFadeMapOffset;
						b = ((b * iFadeMapFactor) >> 8) + iFadeMapOffset;            
						}
					if (iShadowMode & EShadow)
						{
						r = (Max(0,r-0x40));
						g = (Max(0,g-0x40));
						b = (Max(0,b-0x40));                  
						}
					}
				// Convert colour if an incompatible UserDisplayMode is being used
				CDrawBitmap::MapColorToUserDisplayMode(r,g,b);
				*pixelPtr = (r<<16) | (g<<8) | b | 0xff000000;
				}
			aRgbBuffer += 4;
			pixelPtr += pixelPtrInc;
			}
		}
	}

void CDrawUTwentyFourBppBitmap::ReadLine(TInt aX, TInt aY, TInt aLength, TAny* aBuffer, TDisplayMode aDispMode) const
	{
	if (aDispMode == EColor16MAP)
		{
		DeOrientate(aX, aY);
		CDrawThirtyTwoBppBitmapCommon::ReadLine(aX, aY, aLength, aBuffer);
		
		//Overwrite unused byte with 0xff to produce valid 16MAP data
		TUint8* alphaptr = (TUint8*) aBuffer+3;
		TUint8* bufEnd = (TUint8*) aBuffer + (aLength << 2);
		while (alphaptr < bufEnd)
			{
			*alphaptr = 0xff;
			alphaptr+=4;
			}
		
		return;
		}
	CDrawBitmap::ReadLine(aX, aY, aLength, aBuffer, aDispMode);
	}

void CDrawUTwentyFourBppBitmap::BlendRgbMulti(TInt aX,TInt aY,TInt aLength,TInt aHeight,TRgb aColor)
	{
	const TInt sourceAlpha = aColor.Alpha();
	if (sourceAlpha==255)// opaque
		{
		WriteRgbMulti(aX,aY,aLength,aHeight,aColor);
		return;
		}
	if (sourceAlpha==0)// transparent
		return;

	TUint32* pixelPtr = PixelAddress(aX,aY);
	TUint32* pixelRowPtrLimit = pixelPtr + (aHeight * iScanLineWords);
	TUint32* pixelPtrLimit = pixelPtr + aLength;

	const TUint32 sourceInternal=aColor.Internal();
	const TUint32 s_rb = sourceInternal & 0x00FF00FF;
	const TUint32 s_g = (sourceInternal & 0xFF00) >> 8;
	const TUint32 mask2 = sourceAlpha | (sourceAlpha << 16);
	while (pixelPtr < pixelRowPtrLimit)
		{
		for (TUint32* tempPixelPtr = pixelPtr; tempPixelPtr < pixelPtrLimit; tempPixelPtr++)
			{
			const TUint32 d = *tempPixelPtr;
			const TUint32 d_rb = d & 0x00FF00FF;
			const TUint32 rb = ((((sourceAlpha * ((0x01000100 + s_rb) - d_rb)) >> 8) + d_rb) - mask2) & 0x00FF00FF;

			const TInt d_g = (d & 0xFF00) >> 8;
			const TInt g = ((sourceAlpha * (s_g - d_g)) >> 8) + d_g;
	
			*tempPixelPtr = rb | (g<<8) | 0xff000000;
			}

		pixelPtr += iScanLineWords;
		pixelPtrLimit += iScanLineWords;
		}
	}

void CDrawUTwentyFourBppBitmap::BlendLine(TInt aX,TInt aY,TInt aLength,TUint32* aBuffer)
	{
	TUint32* pixelPtr = PixelAddress(aX,aY);

	const TUint32* bufferPtrLimit = aBuffer + aLength;
	const TInt pixelPtrInc = (iOrientation == EOrientationNormal) ? 1 : PixelAddressIncrement();
				
	while (aBuffer < bufferPtrLimit)
		{
		if((*aBuffer &0xFF000000) == 0xFF000000)
			{
			*pixelPtr = *aBuffer;
			}
		else if((*aBuffer & 0xFF000000))
			{	
			// specialization of pre-multiplied blending when the destination alpha is always 255
			const TUint32 src_rb = *aBuffer & 0x00FF00FF;
			const TUint32 src_g = *aBuffer & 0x0000FF00;
			const TUint32 mask = 0x100 - (*aBuffer >> 24);
			TUint32 dst_rb = *pixelPtr & 0x00FF00FF;
			TUint32 dst_g = *pixelPtr & 0x0000FF00;
			dst_rb = (src_rb + ((mask * dst_rb) >> 8)) & 0x00FF00FF;
			dst_g = (src_g + ((mask * dst_g) >> 8)) & 0x0000FF00;
			*pixelPtr = 0xFF000000 | dst_rb | dst_g;
			}
			
		aBuffer++;
		pixelPtr += pixelPtrInc;
		}
	}

TRgb CDrawUTwentyFourBppBitmap::RgbColor(TUint32 aColor) const
	{
	return TRgb::_Color16MU(aColor);
	}

TUint32 CDrawUTwentyFourBppBitmap::Color(const TRgb& aColor)
	{
	return aColor._Color16MA() | 0xff000000;	
	}


// Copies an EColor64K pixel to an EColor16MU screen
FORCEINLINE static void CopyPixel(const TUint16*& aSrcPtr, TUint32*& aDestPtr, TInt aPixelPtrInc, const TUint32* aHighAdd, const TUint16* aLowAdd)
	{
	*aDestPtr = aHighAdd[(*aSrcPtr) >> 8] | aLowAdd[(*aSrcPtr) & 0xff];
	aDestPtr += aPixelPtrInc;
	aSrcPtr++;
	}


// Copies two EColor64K pixels to an EColor16MU screen
FORCEINLINE static void CopyTwoPixels(const TUint32*& aSrcPtr, TUint32*& aDestPtr, TInt aPixelPtrInc, const TUint32* aHighAdd, const TUint16* aLowAdd)
	{
	const TUint16* scanPtr = reinterpret_cast<const TUint16*&>(aSrcPtr);
	*aDestPtr = aHighAdd[(*scanPtr) >> 8] | aLowAdd[(*scanPtr) & 0xff];
 	aDestPtr += aPixelPtrInc;
	scanPtr++;
	*aDestPtr = aHighAdd[(*scanPtr) >> 8] | aLowAdd[(*scanPtr) & 0xff];
 	aDestPtr += aPixelPtrInc;
 	aSrcPtr++;
	}


// Copies an EColor16MU pixel to an EColor16MU screen if necessary.
FORCEINLINE static void ProcessMaskPixel(const TUint32*& aSrcPtr, const TUint32 aMaskWord, TUint32& aSingleBitMask, TUint32*& aDestPtr, TInt aPixelPtrInc)
	{
	if (aMaskWord & aSingleBitMask)
		{
		*aDestPtr = *aSrcPtr;
		}
	aSrcPtr++;
	aDestPtr += aPixelPtrInc;
	aSingleBitMask <<= 1;
	}


// Copies an EColor64K pixel to an EColor16MU screen if necessary.	
FORCEINLINE static void ProcessMaskPixel(const TUint16*& aSrcPtr, const TUint32 aMaskWord, TUint32& aSingleBitMask, TUint32*& aDestPtr, TInt aPixelPtrInc, const TUint32* aHighAdd, const TUint16* aLowAdd)
	{	
	if (aMaskWord & aSingleBitMask)
		{
		*aDestPtr = aHighAdd[(*aSrcPtr) >> 8] | aLowAdd[(*aSrcPtr) & 0xff];
		}
	aSrcPtr++;
	aDestPtr += aPixelPtrInc;
	aSingleBitMask <<= 1;
	}


// Alpha-blends an EColor16MU pixel to an EColor16MU screen using a fixed mask value.
FORCEINLINE static void BlendAlphaPixel(const TUint32*& aSrcPtr, const TUint8 aMask, TUint32*& aDestPtr, TInt aPixelPtrInc)
	{
	const TUint32 s = *aSrcPtr++;
	const TUint32 d = *aDestPtr;
	
	// (a)  (mask * src + (255 - mask) * dest) / 255           This ideal formula
	// (b)  ((mask * (src - dest)) >> 8) + dest                A faster approximation to (a)
	// (c)  ((mask * (256 + src - dest) >> 8) + dest - mask    Equivalent to (b) but can be used on multiple colors at a time

	const TUint32 s_rb = s & 0x00FF00FF;
	const TUint32 d_rb = d & 0x00FF00FF;
	const TUint32 mask2 = aMask | (aMask << 16);
	const TUint32 rb = ((((aMask * ((0x01000100 + s_rb) - d_rb)) >> 8) + d_rb) - mask2) & 0x00FF00FF;

	const TInt s_g = (s & 0xFF00) >> 8;
	const TInt d_g = (d & 0xFF00) >> 8;
	const TInt g = ((aMask * (s_g - d_g)) >> 8) + d_g;
	
	*aDestPtr = rb | (g<<8) | 0xff000000;
	aDestPtr += aPixelPtrInc;
	}


// Alpha-blends an EColor16MU pixel to an EColor16MU screen if necessary.	
FORCEINLINE static void ProcessAlphaPixel(const TUint32*& aSrcPtr, const TUint8*& aMaskPtr, TUint32*& aDestPtr, TInt aPixelPtrInc)
	{
	const TInt mask = *aMaskPtr++;

	if (!mask)
		{
		// pixel is masked
		aSrcPtr++;
		aDestPtr += aPixelPtrInc;
		}
	else if (mask == 0xFF)
		{
		// pixel is unmasked
		*aDestPtr = *aSrcPtr++;
		aDestPtr += aPixelPtrInc;
		}
	else
		{
		BlendAlphaPixel(aSrcPtr, mask, aDestPtr, aPixelPtrInc);
		}
	}
	

// Alpha-blends an EColor64K pixel to an EColor16MU screen using a fixed mask value.
FORCEINLINE static void BlendAlphaPixel(const TUint16*& aSrcPtr, const TUint8 aMask, TUint32*& aDestPtr, TInt aPixelPtrInc)
	{
	const TUint32 s = *aSrcPtr++;
	const TUint32 d = *aDestPtr;
	
	// convert the source EColor64K red / blue pixels to EColor16MU
	// the top two bits in EColor64K are used to fill the bottom two bits in EColor16MU
	
	const TUint32 s_rb = ((s & 0xF800) << 8) | ((s & 0xE000) << 3) | ((s & 0x1F) << 3) | ((s & 0x1C) >>2);	
	const TUint32 d_rb = d & 0x00FF00FF;
	const TUint32 mask2 = aMask | (aMask << 16);
	const TUint32 rb = ((((aMask * ((0x01000100 + s_rb) - d_rb)) >> 8) + d_rb) - mask2) & 0x00FF00FF;
	
	// convert the source EColor64K green pixel to EColor16MU
	const TInt s_g = ((s & 0x07E0) >> 3) | ((s & 0x0600) >> 9);
	const TInt d_g = (d & 0xFF00) >> 8;
	const TInt g = ((aMask * (s_g - d_g)) >> 8) + d_g;
	
	*aDestPtr = rb | (g<<8) | 0xff000000;
	aDestPtr += aPixelPtrInc;
	}

	
// Alpha-blends an EColor64K pixel to an EColor16MU screen if necessary.	
FORCEINLINE static void ProcessAlphaPixel(const TUint16*& aSrcPtr, const TUint8*& aMaskPtr, TUint32*& aDestPtr, TInt aPixelPtrInc, const TUint32* aHighAdd, const TUint16* aLowAdd)
	{
	const TInt mask = *aMaskPtr++;

	if (!mask)
		{
		// pixel is masked
		aSrcPtr++;
		aDestPtr += aPixelPtrInc;
		}
	else if (mask == 0xFF) 
		{
		// pixel is unmasked
		CopyPixel(aSrcPtr, aDestPtr, aPixelPtrInc, aHighAdd, aLowAdd);
		}
	else
		{
		BlendAlphaPixel(aSrcPtr, mask, aDestPtr, aPixelPtrInc);
		}
	}


/**
CDrawUTwentyFourBppBitmap::WriteAlphaLineEx() implementation.
@internalTechnology
@see MFastBlit::WriteAlphaLineEx()
*/
void CDrawUTwentyFourBppBitmap::WriteAlphaLineEx(TInt aX, TInt aY, TInt aLength, TInt aSrcX,
													const TUint32* aSrcPtr,  TDisplayMode aSrcFormat,
													TInt aMaskX, const TUint32* aMaskPtr,
													MAlphaBlend::TShadowing aShadowing)
	{
	// Only certain pixel formats are supported.  Caller should check this.
	__ASSERT_DEBUG(aSrcFormat ==EColor16MU || aSrcFormat ==EColor64K, User::Invariant());
	
	DeOrientate(aX,aY);
	TUint32* pixelPtr = PixelAddress(aX,aY);
	const TInt pixelPtrInc = PixelAddressIncrement();
	
	if (aSrcFormat==EColor16MU)
		{		
		if (!(iShadowMode & EFade) && !(iShadowMode & EShadow) && ((iUserDispMode==ENone) || (iUserDispMode==EColor16MU)) )
			{
			aSrcPtr += aSrcX;
			const TUint32* maskWordPtr = aMaskPtr + (aMaskX >> 2);
			const TInt startBit = aMaskX & 0x3;
			
			if (startBit)
				{
				// Process initial incomplete mask word
				const TUint32 maskWord = *maskWordPtr++;
				TInt numPix = Min(aLength, 4 - startBit);  // number of pixels to process from the first word of the mask
				aLength -= numPix;
				
				if (!maskWord)
					{
					// maskWord is fully masked - skip the pixels
					aSrcPtr += numPix;
					pixelPtr += pixelPtrInc * numPix;
					}
				else if (maskWord == 0xFFFFFFFF)
					{
					// maskWord is fully unmasked - copy the pixels
					while (numPix--)
						{
						*pixelPtr = *aSrcPtr++;
						pixelPtr += pixelPtrInc;
						}
					}
				else
					{
					// At least one of the pixels needs to be blended
					const TUint8* maskPtr8 = reinterpret_cast<const TUint8*>(&maskWord);
					maskPtr8 += startBit;
					while (numPix--)
						{
						ProcessAlphaPixel(aSrcPtr, maskPtr8, pixelPtr, pixelPtrInc);
						}
					}
				}
			
			TInt numMaskWords = aLength >> 2;
			aLength &= 0x3;
			while (numMaskWords--)
				{
				// Process a complete mask word - 4 pixels
				const TUint32 maskWord = *maskWordPtr++;
				
				if (!maskWord)
					{
					// maskWord is fully masked - skip 4 pixels
					aSrcPtr += 4;
					pixelPtr += pixelPtrInc << 2;
					}
				else if (maskWord == 0xFFFFFFFF)
					{
					// maskWord is fully unmasked - copy 4 pixels
					*pixelPtr = *aSrcPtr++; pixelPtr += pixelPtrInc;
					*pixelPtr = *aSrcPtr++; pixelPtr += pixelPtrInc;
					*pixelPtr = *aSrcPtr++; pixelPtr += pixelPtrInc;
					*pixelPtr = *aSrcPtr++; pixelPtr += pixelPtrInc;
					}
				else
					{	
					// At least one of the 4 pixels needs to be blended
					const TUint8* maskPtr8 = reinterpret_cast<const TUint8*>(&maskWord);

					if (maskPtr8[0] && (maskPtr8[0] != 0xFF) &&
						maskPtr8[1] && (maskPtr8[1] != 0xFF) &&
						maskPtr8[2] && (maskPtr8[2] != 0xFF) &&
						maskPtr8[3] && (maskPtr8[3] != 0xFF))
						{
						// Blend all 4 pixels inline
						BlendAlphaPixel(aSrcPtr, maskPtr8[0], pixelPtr, pixelPtrInc);
						BlendAlphaPixel(aSrcPtr, maskPtr8[1], pixelPtr, pixelPtrInc);
						BlendAlphaPixel(aSrcPtr, maskPtr8[2], pixelPtr, pixelPtrInc);
						BlendAlphaPixel(aSrcPtr, maskPtr8[3], pixelPtr, pixelPtrInc);
						}
					else
						{
						ProcessAlphaPixel(aSrcPtr, maskPtr8, pixelPtr, pixelPtrInc);
						ProcessAlphaPixel(aSrcPtr, maskPtr8, pixelPtr, pixelPtrInc);
						ProcessAlphaPixel(aSrcPtr, maskPtr8, pixelPtr, pixelPtrInc);
						ProcessAlphaPixel(aSrcPtr, maskPtr8, pixelPtr, pixelPtrInc);
						}
					}
				}

			if (aLength)
				{
				const TUint32 maskWord = *maskWordPtr;
				if (!maskWord)
					{
					// maskWord is fully masked - skip the pixels
					return;
					}
				if (maskWord == 0xFFFFFFFF)
					{
					// maskWord is fully unmasked - copy the pixels
					while (aLength--)
						{
						*pixelPtr = *aSrcPtr++;
						pixelPtr += pixelPtrInc;
						}
					}
				else
					{
					// At least one of the pixels needs to be blended
					const TUint8* maskPtr8 = reinterpret_cast<const TUint8*>(&maskWord);
					while (aLength--)
						{
						ProcessAlphaPixel(aSrcPtr, maskPtr8, pixelPtr, pixelPtrInc);
						}
					}
				}
			}
		else
			{
			// Non-optimised path including shadowing and UserDisplayMode conversion
			const TUint8* srcPtr8  = reinterpret_cast<const TUint8*>(aSrcPtr + aSrcX);
			const TUint8* maskPtr8 = reinterpret_cast<const TUint8*>(aMaskPtr) + aMaskX;
			
			while (aLength--)
				{
				TInt mask = *maskPtr8++;
				if (mask)
					{
					TInt b = srcPtr8[0];
					TInt g = srcPtr8[1];
					TInt r = srcPtr8[2];
					if(aShadowing == MAlphaBlend::EShdwBefore)
						{
						if (iShadowMode & EFade)
							{
							r = ((r * iFadeMapFactor) >> 8) + iFadeMapOffset;
							g = ((g * iFadeMapFactor) >> 8) + iFadeMapOffset;
							b = ((b * iFadeMapFactor) >> 8) + iFadeMapOffset;
							}
						if (iShadowMode & EShadow)
							{
							r = (Max(0,r-0x40));
							g = (Max(0,g-0x40));
							b = (Max(0,b-0x40));
							}
						}
					if (mask != 0xff)
						{
						// (mask * r + (255 - mask) * value) / 255 =
						// ((257 * mask * (r - value)) >> 16) + value
						TInt value = *pixelPtr & 0xffffff;
						mask = (mask << 8) + mask; // mask = mask * 257
						TInt v = value >> 16;
						r = ((mask * (r - v)) >> 16) + v;
						v = (value >> 8) & 0xff;
						g = ((mask * (g - v)) >> 16) + v;
						v = value & 0xff;
						b = ((mask * (b - v)) >> 16) + v;
						}
					if(aShadowing == MAlphaBlend::EShdwAfter)
						{
						if (iShadowMode & EFade)
							{  
							r = ((r * iFadeMapFactor) >> 8) + iFadeMapOffset;
							g = ((g * iFadeMapFactor) >> 8) + iFadeMapOffset;
							b = ((b * iFadeMapFactor) >> 8) + iFadeMapOffset;            
							}
						if (iShadowMode & EShadow)
							{
							r = (Max(0,r-0x40));
							g = (Max(0,g-0x40));
							b = (Max(0,b-0x40));
							}
						}
					// Convert colour if an incompatible UserDisplayMode is being used
					CDrawBitmap::MapColorToUserDisplayMode(r,g,b);
					*pixelPtr = (r<<16) | (g<<8) | b | 0xff000000;
					}
				pixelPtr += pixelPtrInc;
				srcPtr8 += 4;
				}
			}
		return;
		}
	else   // (aSrcFormat==EColor64K)
		{
		const TUint16* srcPtr16 = reinterpret_cast<const TUint16*>(aSrcPtr) + aSrcX;
		
		if (!(iShadowMode & EFade) && !(iShadowMode & EShadow) && ((iUserDispMode==ENone) || (iUserDispMode==EColor16MU)))
			{			
			const TUint16* lowAdd = Convert16to32bppLow();
			const TUint32* highAdd = Convert16to32bppHigh();
			const TUint32* maskWordPtr = aMaskPtr + (aMaskX >> 2);
			const TInt startBit = aMaskX & 0x3;
			
			if (startBit)
				{
				// Process initial incomplete mask word
				const TUint32 maskWord = *maskWordPtr++;
				TInt numPix = Min(aLength, 4 - startBit);  // number of pixels to process from the first word of the mask
				aLength -= numPix;
				
				if (!maskWord)
					{
					// maskWord is fully masked
					srcPtr16 += numPix;
					pixelPtr += pixelPtrInc * numPix;
					}
				else if (maskWord == 0xFFFFFFFF)
					{
					// maskWord is fully unmasked
					while (numPix--)
						{
						CopyPixel(srcPtr16, pixelPtr, pixelPtrInc, highAdd, lowAdd);
						}
					}
				else
					{
					// At least one of the pixels needs to be blended
					const TUint8* maskPtr8 = reinterpret_cast<const TUint8*>(&maskWord);
					maskPtr8 += startBit;
					while (numPix--)
						{
						ProcessAlphaPixel(srcPtr16, maskPtr8, pixelPtr, pixelPtrInc, highAdd, lowAdd);
						}
					}
				}
			
			TInt numMaskWords = aLength >> 2;
			aLength &= 0x3;
			while (numMaskWords--)
				{
				// Process 4 mask pixels
				const TUint32 maskWord = *maskWordPtr++;
				
				if (!maskWord)
					{
					// maskWord is fully masked - skip 4 pixels
					srcPtr16 += 4;
					pixelPtr += pixelPtrInc << 2;
					}
				else if (maskWord == 0xFFFFFFFF)
					{
					// maskWord is fully unmasked - copy and convert 4 pixels
					const TUint32* srcPtr32 = (const TUint32*)srcPtr16;
					CopyTwoPixels(srcPtr32, pixelPtr, pixelPtrInc, highAdd, lowAdd);
					CopyTwoPixels(srcPtr32, pixelPtr, pixelPtrInc, highAdd, lowAdd);
					srcPtr16 = (const TUint16*)srcPtr32;
					}
				else
					{	
					// At least one of the 4 pixels needs to be blended
					const TUint8* maskPtr8 = reinterpret_cast<const TUint8*>(&maskWord);

					if (maskPtr8[0] && (maskPtr8[0] != 0xFF) &&
						maskPtr8[1] && (maskPtr8[1] != 0xFF) &&
						maskPtr8[2] && (maskPtr8[2] != 0xFF) &&
						maskPtr8[3] && (maskPtr8[3] != 0xFF))
						{
						// Blend all 4 pixels inline
						BlendAlphaPixel(srcPtr16, maskPtr8[0], pixelPtr, pixelPtrInc);
						BlendAlphaPixel(srcPtr16, maskPtr8[1], pixelPtr, pixelPtrInc);
						BlendAlphaPixel(srcPtr16, maskPtr8[2], pixelPtr, pixelPtrInc);
						BlendAlphaPixel(srcPtr16, maskPtr8[3], pixelPtr, pixelPtrInc);
						}
					else
						{
						ProcessAlphaPixel(srcPtr16, maskPtr8, pixelPtr, pixelPtrInc, highAdd, lowAdd);
						ProcessAlphaPixel(srcPtr16, maskPtr8, pixelPtr, pixelPtrInc, highAdd, lowAdd);
						ProcessAlphaPixel(srcPtr16, maskPtr8, pixelPtr, pixelPtrInc, highAdd, lowAdd);
						ProcessAlphaPixel(srcPtr16, maskPtr8, pixelPtr, pixelPtrInc, highAdd, lowAdd);
						}
					}
				}

			if (aLength)
				{
				// Process final incomplete mask word
				const TUint32 maskWord = *maskWordPtr;   // this will over-read
				if (!maskWord)
					{
					// maskWord is fully masked	- skip the pixels
					return;
					}
				if (maskWord == 0xFFFFFFFF)
					{
					// maskWord is fully unmasked - copy and convert the pixels
					while (aLength--)
						{
						CopyPixel(srcPtr16, pixelPtr, pixelPtrInc, highAdd, lowAdd);
						}
					}
				else
					{
					// At least one of the pixels needs to be blended
					const TUint8* maskPtr8 = reinterpret_cast<const TUint8*>(&maskWord);
					while (aLength--)
						{
						ProcessAlphaPixel(srcPtr16, maskPtr8, pixelPtr, pixelPtrInc, highAdd, lowAdd);
						}
					}
				}
			}
		else
			{
			// Non-optimised path including shadowing and UserDisplayMode conversion
			const TUint8* maskPtr8  = reinterpret_cast<const TUint8*>(aMaskPtr) + aMaskX;
			while (aLength--)
				{
				TInt mask = *maskPtr8++;
				if (mask)
					{
					const TUint32 src = *srcPtr16;
					TInt r  = (src & 0xF800) >> 8;
					     r |= (src & 0xE000) >>13;
					TInt g  = (src & 0x07E0) >> 3;
					     g |= (src & 0x0600) >> 9;
					TInt b  = (src & 0x001F) << 3;
					     b |= (src & 0x001C) >> 2;

					if(aShadowing == MAlphaBlend::EShdwBefore)
						{
						if (iShadowMode & EFade)
							{
							r = ((r * iFadeMapFactor) >> 8) + iFadeMapOffset;
							g = ((g * iFadeMapFactor) >> 8) + iFadeMapOffset;
							b = ((b * iFadeMapFactor) >> 8) + iFadeMapOffset;
							}
						if (iShadowMode & EShadow)
							{
							r = Max(0,r-0x40);
							g = Max(0,g-0x40);
							b = Max(0,b-0x40);
							}
						}
					if (mask != 0xff)
						{
						// (mask * r + (255 - mask) * value) / 255 =
						// ((257 * mask * (r - value)) >> 16) + value
						const TInt value = *pixelPtr & 0xffffff;
						mask = (mask << 8) + mask; // mask = mask * 257
						TInt v = value >> 16;
						r = ((mask * (r - v)) >> 16) + v;
						v = (value >> 8) & 0xff;
						g = ((mask * (g - v)) >> 16) + v;
						v = value & 0xff;
						b = ((mask * (b - v)) >> 16) + v;
						}
					if(aShadowing == MAlphaBlend::EShdwAfter)
						{
						if (iShadowMode & EFade)
							{  
							r = ((r * iFadeMapFactor) >> 8) + iFadeMapOffset;
							g = ((g * iFadeMapFactor) >> 8) + iFadeMapOffset;
							b = ((b * iFadeMapFactor) >> 8) + iFadeMapOffset;            
							}
						if (iShadowMode & EShadow)
							{
							r = Max(0,r-0x40);
							g = Max(0,g-0x40);
							b = Max(0,b-0x40);                  
							}
						}
					// Convert colour if an incompatible UserDisplayMode is being used
					CDrawBitmap::MapColorToUserDisplayMode(r,g,b);
					*pixelPtr = (r<<16) | (g<<8) | b | 0xff000000;
					}
				srcPtr16++;
				pixelPtr += pixelPtrInc;
				}
			}
		return;
		}	
	}

/**
CDrawUTwentyFourBppBitmap::WriteMaskLineEx() implementation.
@internalTechnology
@see MFastBlit::WriteMaskLineEx()
*/
void CDrawUTwentyFourBppBitmap::WriteMaskLineEx(TInt aX, TInt aY, TInt aLength, TInt aSrcX,
													const TUint32* aSrcPtr,  TDisplayMode aSrcFormat,
													TInt aMaskX, const TUint32* aMaskPtr, TBool aInvertMask)
	{
	// Only certain pixel formats are supported.  Caller should check this.
	__ASSERT_DEBUG(aSrcFormat ==EColor16MU || aSrcFormat ==EColor64K, User::Invariant());

	DeOrientate(aX,aY);
	TUint32* pixelPtr = PixelAddress(aX,aY);
	const TInt pixelPtrInc = PixelAddressIncrement();
	const TUint32 invertWord = (aInvertMask ? 0xFFFFFFFF : 0);  // to be XORed with the mask

	if (aSrcFormat==EColor16MU)
		{
		aSrcPtr += aSrcX;
	
		if ((iUserDispMode==ENone) || (iUserDispMode==EColor16MU))
			{
			const TUint32* maskWordPtr = aMaskPtr + (aMaskX >> 5);
			const TInt startBit = aMaskX & 0x1F;

			if (startBit)
				{
				// Process initial incomplete mask word
				TUint32 maskWord = *maskWordPtr++;
				maskWord ^= invertWord;
				TInt numPix = Min(aLength, 32 - startBit);  // number of pixels to process from the first word of the mask
				aLength -= numPix;

				if (!maskWord)
					{
					// maskWord is fully masked - skip the pixels
					aSrcPtr += numPix;
					pixelPtr += pixelPtrInc * numPix;
					}
				else if (maskWord == 0xFFFFFFFF)
					{
					// maskWord is fully unmasked - copy the pixels
					while (numPix--)
						{
						*pixelPtr = *aSrcPtr++;
						pixelPtr += pixelPtrInc;
						}
					}
				else
					{
					// maskWord is partially masked - process each pixel
					TUint32 singleBitMask = 1 << startBit;
					while (numPix--)
						{
						ProcessMaskPixel(aSrcPtr, maskWord, singleBitMask, pixelPtr, pixelPtrInc);
						}
					}
				}
			
			TInt numMaskWords = aLength >> 5;
			aLength &= 0x1F;
			while (numMaskWords--)
				{
				// Process a complete mask word (32 pixels)
				TUint32 maskWord = *maskWordPtr++;
				maskWord ^= invertWord;
				
				if (!maskWord)
					{
					// maskWord is fully masked - skip 32 pixels
					aSrcPtr += 32;
					pixelPtr += pixelPtrInc << 5;
					}
				else if (maskWord == 0xFFFFFFFF)
					{
					// maskWord is fully unmasked - copy 32 pixels
					if (pixelPtrInc==1)
						{
						pixelPtr=(TUint32*)Mem::Move(pixelPtr, aSrcPtr, 128);
						aSrcPtr+= 32;
						}
					else
						{
						*pixelPtr = *aSrcPtr++; pixelPtr += pixelPtrInc;
						*pixelPtr = *aSrcPtr++; pixelPtr += pixelPtrInc;
						*pixelPtr = *aSrcPtr++; pixelPtr += pixelPtrInc;
						*pixelPtr = *aSrcPtr++; pixelPtr += pixelPtrInc;
						*pixelPtr = *aSrcPtr++; pixelPtr += pixelPtrInc;
						*pixelPtr = *aSrcPtr++; pixelPtr += pixelPtrInc;
						*pixelPtr = *aSrcPtr++; pixelPtr += pixelPtrInc;
						*pixelPtr = *aSrcPtr++; pixelPtr += pixelPtrInc;
						*pixelPtr = *aSrcPtr++; pixelPtr += pixelPtrInc;
						*pixelPtr = *aSrcPtr++; pixelPtr += pixelPtrInc;
						*pixelPtr = *aSrcPtr++; pixelPtr += pixelPtrInc;
						*pixelPtr = *aSrcPtr++; pixelPtr += pixelPtrInc;
						*pixelPtr = *aSrcPtr++; pixelPtr += pixelPtrInc;
						*pixelPtr = *aSrcPtr++; pixelPtr += pixelPtrInc;
						*pixelPtr = *aSrcPtr++; pixelPtr += pixelPtrInc;
						*pixelPtr = *aSrcPtr++; pixelPtr += pixelPtrInc;
						*pixelPtr = *aSrcPtr++; pixelPtr += pixelPtrInc;
						*pixelPtr = *aSrcPtr++; pixelPtr += pixelPtrInc;
						*pixelPtr = *aSrcPtr++; pixelPtr += pixelPtrInc;
						*pixelPtr = *aSrcPtr++; pixelPtr += pixelPtrInc;
						*pixelPtr = *aSrcPtr++; pixelPtr += pixelPtrInc;
						*pixelPtr = *aSrcPtr++; pixelPtr += pixelPtrInc;
						*pixelPtr = *aSrcPtr++; pixelPtr += pixelPtrInc;
						*pixelPtr = *aSrcPtr++; pixelPtr += pixelPtrInc;
						*pixelPtr = *aSrcPtr++; pixelPtr += pixelPtrInc;
						*pixelPtr = *aSrcPtr++; pixelPtr += pixelPtrInc;
						*pixelPtr = *aSrcPtr++; pixelPtr += pixelPtrInc;
						*pixelPtr = *aSrcPtr++; pixelPtr += pixelPtrInc;
						*pixelPtr = *aSrcPtr++; pixelPtr += pixelPtrInc;
						*pixelPtr = *aSrcPtr++; pixelPtr += pixelPtrInc;
						*pixelPtr = *aSrcPtr++; pixelPtr += pixelPtrInc;
						*pixelPtr = *aSrcPtr++; pixelPtr += pixelPtrInc;
						}
					}
				else
					{	
					// maskWord is partially masked - process each of the 32 pixels
					TUint32 singleBitMask = 1;
					ProcessMaskPixel(aSrcPtr, maskWord, singleBitMask, pixelPtr, pixelPtrInc);
					ProcessMaskPixel(aSrcPtr, maskWord, singleBitMask, pixelPtr, pixelPtrInc);
					ProcessMaskPixel(aSrcPtr, maskWord, singleBitMask, pixelPtr, pixelPtrInc);
					ProcessMaskPixel(aSrcPtr, maskWord, singleBitMask, pixelPtr, pixelPtrInc);
					ProcessMaskPixel(aSrcPtr, maskWord, singleBitMask, pixelPtr, pixelPtrInc);
					ProcessMaskPixel(aSrcPtr, maskWord, singleBitMask, pixelPtr, pixelPtrInc);
					ProcessMaskPixel(aSrcPtr, maskWord, singleBitMask, pixelPtr, pixelPtrInc);
					ProcessMaskPixel(aSrcPtr, maskWord, singleBitMask, pixelPtr, pixelPtrInc);
					ProcessMaskPixel(aSrcPtr, maskWord, singleBitMask, pixelPtr, pixelPtrInc);
					ProcessMaskPixel(aSrcPtr, maskWord, singleBitMask, pixelPtr, pixelPtrInc);
					ProcessMaskPixel(aSrcPtr, maskWord, singleBitMask, pixelPtr, pixelPtrInc);
					ProcessMaskPixel(aSrcPtr, maskWord, singleBitMask, pixelPtr, pixelPtrInc);
					ProcessMaskPixel(aSrcPtr, maskWord, singleBitMask, pixelPtr, pixelPtrInc);
					ProcessMaskPixel(aSrcPtr, maskWord, singleBitMask, pixelPtr, pixelPtrInc);
					ProcessMaskPixel(aSrcPtr, maskWord, singleBitMask, pixelPtr, pixelPtrInc);
					ProcessMaskPixel(aSrcPtr, maskWord, singleBitMask, pixelPtr, pixelPtrInc);
					ProcessMaskPixel(aSrcPtr, maskWord, singleBitMask, pixelPtr, pixelPtrInc);
					ProcessMaskPixel(aSrcPtr, maskWord, singleBitMask, pixelPtr, pixelPtrInc);
					ProcessMaskPixel(aSrcPtr, maskWord, singleBitMask, pixelPtr, pixelPtrInc);
					ProcessMaskPixel(aSrcPtr, maskWord, singleBitMask, pixelPtr, pixelPtrInc);
					ProcessMaskPixel(aSrcPtr, maskWord, singleBitMask, pixelPtr, pixelPtrInc);
					ProcessMaskPixel(aSrcPtr, maskWord, singleBitMask, pixelPtr, pixelPtrInc);
					ProcessMaskPixel(aSrcPtr, maskWord, singleBitMask, pixelPtr, pixelPtrInc);
					ProcessMaskPixel(aSrcPtr, maskWord, singleBitMask, pixelPtr, pixelPtrInc);
					ProcessMaskPixel(aSrcPtr, maskWord, singleBitMask, pixelPtr, pixelPtrInc);
					ProcessMaskPixel(aSrcPtr, maskWord, singleBitMask, pixelPtr, pixelPtrInc);
					ProcessMaskPixel(aSrcPtr, maskWord, singleBitMask, pixelPtr, pixelPtrInc);
					ProcessMaskPixel(aSrcPtr, maskWord, singleBitMask, pixelPtr, pixelPtrInc);
					ProcessMaskPixel(aSrcPtr, maskWord, singleBitMask, pixelPtr, pixelPtrInc);
					ProcessMaskPixel(aSrcPtr, maskWord, singleBitMask, pixelPtr, pixelPtrInc);
					ProcessMaskPixel(aSrcPtr, maskWord, singleBitMask, pixelPtr, pixelPtrInc);
					ProcessMaskPixel(aSrcPtr, maskWord, singleBitMask, pixelPtr, pixelPtrInc);
					}
				}


			if (aLength)
				{
				// Process final incomplete mask word
				TUint32 maskWord = *maskWordPtr;
				maskWord ^= invertWord;
				
				if (!maskWord)
					{
					// maskWord is fully masked - skip the pixels
					return;
					}
				if (maskWord == 0xFFFFFFFF)
					{
					// maskWord is fully unmasked - copy the pixels
					while (aLength--)
						{
						*pixelPtr = *aSrcPtr++;
						pixelPtr += pixelPtrInc;
						}
					}
				else
					{
					// maskWord is partially masked - process each pixel
					TUint32 singleBitMask = 1;
					while (aLength--)
						{
						ProcessMaskPixel(aSrcPtr, maskWord, singleBitMask, pixelPtr, pixelPtrInc);
						}
					}
				}
			}
		else
			{
			// Non-optimised path.  UserDisplay mode is different to the true display mode
			while (aLength--)
				{
				TUint32 mask = *(aMaskPtr + (aMaskX >> 5)) & (1 << (aMaskX & 0x1F));
				if (aInvertMask)
					{
					mask = !mask;
					}
				if (mask)
					{
					TRgb pixel(*aSrcPtr);
					MapColorToUserDisplayMode(pixel);
					*pixelPtr = pixel.Value();
					}
				aSrcPtr++;
				aMaskX++;
				pixelPtr += pixelPtrInc;
				}
			}
		return;
		}
	else  // (aSrcFormat==EColor64K)
		{
		const TUint16* srcPtr16 = reinterpret_cast<const TUint16*>(aSrcPtr) + aSrcX;
	
		if ((iUserDispMode==ENone) || (iUserDispMode==EColor16MU))
			{
			const TUint16* lowAdd = Convert16to32bppLow();
			const TUint32* highAdd = Convert16to32bppHigh();
			const TUint32* maskWordPtr = aMaskPtr + (aMaskX >> 5);
			const TInt startBit = aMaskX & 0x1F;
			
			if (startBit)
				{
				// Process initial incomplete mask word
				TUint32 maskWord = *maskWordPtr++;
				maskWord ^= invertWord;
				TInt numPix = Min(aLength, 32 - startBit);  // number of pixels to process from the first word of the mask
				aLength -= numPix;
				
				if (!maskWord)
					{
					// maskWord is fully masked	- skip the pixels
					srcPtr16 += numPix;
					pixelPtr += pixelPtrInc * numPix;
					}
				else if (maskWord == 0xFFFFFFFF)
					{
					// maskWord is fully unmasked - copy and convert the pixels
					while (numPix--)
						{
						CopyPixel(srcPtr16, pixelPtr, pixelPtrInc, highAdd, lowAdd);
						}
					}
				else
					{
					// maskWord is partially masked - process each of the pixels
					TUint32 singleBitMask = 1 << startBit;
					while (numPix--)
						{
						ProcessMaskPixel(srcPtr16, maskWord, singleBitMask, pixelPtr, pixelPtrInc, highAdd, lowAdd);
						}
					}
				}
			
			TInt numMaskWords = aLength >> 5;
			aLength &= 0x1F;
			while (numMaskWords--)
				{
				// Process complete mask words
				TUint32 maskWord = *maskWordPtr++;
				maskWord ^= invertWord;
				
				if (!maskWord)
					{
					// maskWord is fully masked - skip 32 pixels
					srcPtr16 += 32;
					pixelPtr += pixelPtrInc << 5;
					}
				else if (maskWord == 0xFFFFFFFF)
					{
					// maskWord is fully unmasked - copy and convert 32 pixels
					const TUint32* srcPtr32 = (const TUint32*)srcPtr16;
					CopyTwoPixels(srcPtr32, pixelPtr, pixelPtrInc, highAdd, lowAdd);
					CopyTwoPixels(srcPtr32, pixelPtr, pixelPtrInc, highAdd, lowAdd);
					CopyTwoPixels(srcPtr32, pixelPtr, pixelPtrInc, highAdd, lowAdd);
					CopyTwoPixels(srcPtr32, pixelPtr, pixelPtrInc, highAdd, lowAdd);
					CopyTwoPixels(srcPtr32, pixelPtr, pixelPtrInc, highAdd, lowAdd);
					CopyTwoPixels(srcPtr32, pixelPtr, pixelPtrInc, highAdd, lowAdd);
					CopyTwoPixels(srcPtr32, pixelPtr, pixelPtrInc, highAdd, lowAdd);
					CopyTwoPixels(srcPtr32, pixelPtr, pixelPtrInc, highAdd, lowAdd);
					CopyTwoPixels(srcPtr32, pixelPtr, pixelPtrInc, highAdd, lowAdd);
					CopyTwoPixels(srcPtr32, pixelPtr, pixelPtrInc, highAdd, lowAdd);
					CopyTwoPixels(srcPtr32, pixelPtr, pixelPtrInc, highAdd, lowAdd);
					CopyTwoPixels(srcPtr32, pixelPtr, pixelPtrInc, highAdd, lowAdd);
					CopyTwoPixels(srcPtr32, pixelPtr, pixelPtrInc, highAdd, lowAdd);
					CopyTwoPixels(srcPtr32, pixelPtr, pixelPtrInc, highAdd, lowAdd);
					CopyTwoPixels(srcPtr32, pixelPtr, pixelPtrInc, highAdd, lowAdd);
					CopyTwoPixels(srcPtr32, pixelPtr, pixelPtrInc, highAdd, lowAdd);
					srcPtr16 = (const TUint16*)srcPtr32;
					}
				else
					{
					// maskWord is partially masked - process each of the 32 pixels					
					TUint32 singleBitMask = 1;
					ProcessMaskPixel(srcPtr16, maskWord, singleBitMask, pixelPtr, pixelPtrInc, highAdd, lowAdd);
					ProcessMaskPixel(srcPtr16, maskWord, singleBitMask, pixelPtr, pixelPtrInc, highAdd, lowAdd);
					ProcessMaskPixel(srcPtr16, maskWord, singleBitMask, pixelPtr, pixelPtrInc, highAdd, lowAdd);
					ProcessMaskPixel(srcPtr16, maskWord, singleBitMask, pixelPtr, pixelPtrInc, highAdd, lowAdd);
					ProcessMaskPixel(srcPtr16, maskWord, singleBitMask, pixelPtr, pixelPtrInc, highAdd, lowAdd);
					ProcessMaskPixel(srcPtr16, maskWord, singleBitMask, pixelPtr, pixelPtrInc, highAdd, lowAdd);
					ProcessMaskPixel(srcPtr16, maskWord, singleBitMask, pixelPtr, pixelPtrInc, highAdd, lowAdd);
					ProcessMaskPixel(srcPtr16, maskWord, singleBitMask, pixelPtr, pixelPtrInc, highAdd, lowAdd);
					ProcessMaskPixel(srcPtr16, maskWord, singleBitMask, pixelPtr, pixelPtrInc, highAdd, lowAdd);
					ProcessMaskPixel(srcPtr16, maskWord, singleBitMask, pixelPtr, pixelPtrInc, highAdd, lowAdd);
					ProcessMaskPixel(srcPtr16, maskWord, singleBitMask, pixelPtr, pixelPtrInc, highAdd, lowAdd);
					ProcessMaskPixel(srcPtr16, maskWord, singleBitMask, pixelPtr, pixelPtrInc, highAdd, lowAdd);
					ProcessMaskPixel(srcPtr16, maskWord, singleBitMask, pixelPtr, pixelPtrInc, highAdd, lowAdd);
					ProcessMaskPixel(srcPtr16, maskWord, singleBitMask, pixelPtr, pixelPtrInc, highAdd, lowAdd);
					ProcessMaskPixel(srcPtr16, maskWord, singleBitMask, pixelPtr, pixelPtrInc, highAdd, lowAdd);
					ProcessMaskPixel(srcPtr16, maskWord, singleBitMask, pixelPtr, pixelPtrInc, highAdd, lowAdd);
					ProcessMaskPixel(srcPtr16, maskWord, singleBitMask, pixelPtr, pixelPtrInc, highAdd, lowAdd);
					ProcessMaskPixel(srcPtr16, maskWord, singleBitMask, pixelPtr, pixelPtrInc, highAdd, lowAdd);
					ProcessMaskPixel(srcPtr16, maskWord, singleBitMask, pixelPtr, pixelPtrInc, highAdd, lowAdd);
					ProcessMaskPixel(srcPtr16, maskWord, singleBitMask, pixelPtr, pixelPtrInc, highAdd, lowAdd);
					ProcessMaskPixel(srcPtr16, maskWord, singleBitMask, pixelPtr, pixelPtrInc, highAdd, lowAdd);
					ProcessMaskPixel(srcPtr16, maskWord, singleBitMask, pixelPtr, pixelPtrInc, highAdd, lowAdd);
					ProcessMaskPixel(srcPtr16, maskWord, singleBitMask, pixelPtr, pixelPtrInc, highAdd, lowAdd);
					ProcessMaskPixel(srcPtr16, maskWord, singleBitMask, pixelPtr, pixelPtrInc, highAdd, lowAdd);
					ProcessMaskPixel(srcPtr16, maskWord, singleBitMask, pixelPtr, pixelPtrInc, highAdd, lowAdd);
					ProcessMaskPixel(srcPtr16, maskWord, singleBitMask, pixelPtr, pixelPtrInc, highAdd, lowAdd);
					ProcessMaskPixel(srcPtr16, maskWord, singleBitMask, pixelPtr, pixelPtrInc, highAdd, lowAdd);
					ProcessMaskPixel(srcPtr16, maskWord, singleBitMask, pixelPtr, pixelPtrInc, highAdd, lowAdd);
					ProcessMaskPixel(srcPtr16, maskWord, singleBitMask, pixelPtr, pixelPtrInc, highAdd, lowAdd);
					ProcessMaskPixel(srcPtr16, maskWord, singleBitMask, pixelPtr, pixelPtrInc, highAdd, lowAdd);
					ProcessMaskPixel(srcPtr16, maskWord, singleBitMask, pixelPtr, pixelPtrInc, highAdd, lowAdd);
					ProcessMaskPixel(srcPtr16, maskWord, singleBitMask, pixelPtr, pixelPtrInc, highAdd, lowAdd);
					}
				}
			
			if (aLength)
				{
				// Process final incomplete mask word
				TUint32 maskWord = *maskWordPtr;		// this will over-read
				maskWord ^= invertWord;
				
				if (!maskWord)
					{
					// maskWord is masked - skip the pixels
					return;
					}
					
				if (maskWord == 0xFFFFFFFF)
					{
					// maskWord is fully unmasked - copy and convert the pixels
					while (aLength--)
						{
						CopyPixel(srcPtr16, pixelPtr, pixelPtrInc, highAdd, lowAdd);
						}
					}
				else
					{
					// maskWord is partially masked - process each of the pixels
					TUint32 singleBitMask = 1;
					while (aLength--)
						{
						ProcessMaskPixel(srcPtr16, maskWord, singleBitMask, pixelPtr, pixelPtrInc, highAdd, lowAdd);
						}
					}
				}
			}
		else
			{
			// Non-optimised - expects aMaskPtr untouched and srcPtr16 to be accurate
			while (aLength--)
				{
				TUint32 mask = *(aMaskPtr + (aMaskX >> 5)) & (1 << (aMaskX & 0x1F));
				if (aInvertMask)
					{
					mask = !mask;
					}
				if (mask)
					{
					const TUint32 src = *srcPtr16;
					TUint32 color = (src & 0xF800) << 8; // R top 5
					color |= (src & 0xE000) << 3; // R bottom 3 
					color |= (src & 0x07E0) << 5; // G top 6
					color |= (src & 0x0600) >> 1; // G bottom 2
					color |= (src & 0x001F) << 3; // B top 5
					color |= (src & 0x001C) >> 2; // B bottom 3
					TRgb pixel(color);
					MapColorToUserDisplayMode(pixel);
					*pixelPtr = pixel.Value();
					}
				pixelPtr += pixelPtrInc;
				srcPtr16++;
				aMaskX++;
				}
			}
		return;
		}
	}

/**
Implementation for CFbsDrawDevice::GetInterface().
Retrieves a pointer to a specified interface of CFbsDrawDevice implementation.
@param aInterfaceId Interface identifier of the interface to be retrieved.
@param aInterface Address of variable that retrieves the specified interface.
@return KErrNone If the interface is supported, KErrNotSupported otherwise.
*/
TInt CDrawUTwentyFourBppBitmap::GetInterface(TInt aInterfaceId, TAny*& aInterface)
	{
	aInterface = NULL;
	TInt ret = KErrNotSupported;
	
	switch (aInterfaceId)
		{
		case KFastBlitInterfaceID:
			{
			aInterface = static_cast<MFastBlit*>(this);
			ret = KErrNone;
			break;
			}
		default:
			{
			return CDrawThirtyTwoBppBitmapCommon::GetInterface(aInterfaceId, aInterface);
			}
		}
		
	return ret;
	}

TInt CDrawUTwentyFourBppBitmap::WriteRgbOutlineAndShadow(TInt aX, TInt aY, const TInt aLength,
														TUint32 aOutlinePenColor, TUint32 aShadowColor,
														TUint32 aFillColor, const TUint8* aDataBuffer)
	{
	const TInt alpha = aOutlinePenColor >> 24;
	if (alpha==0 || aLength<=0)
		return KErrNone;
	DeOrientate(aX,aY);
	TUint32* pixelPtr = PixelAddress(aX,aY);
	const TInt pixelPtrInc = PixelAddressIncrement();
	const TUint8* dataBufferPtrLimit = aDataBuffer + aLength;
	TInt blendedRedColor;
	TInt blendedGreenColor;
	TInt blendedBlueColor;
	TUint8 index = 0;
	TUint32 finalColor;

	//Get red color. Equivalent to TRgb::Red()
	const TInt redOutlinePenColor = (aOutlinePenColor & 0xff0000) >> 16;
	const TInt redShadowColor = (aShadowColor & 0xff0000) >> 16;
	const TInt redFillColor = (aFillColor & 0xff0000) >> 16;

	//Get green color. Equivalent to TRgb::Green()
	const TInt greenOutlinePenColor = (aOutlinePenColor & 0xff00) >> 8;
	const TInt greenShadowColor = (aShadowColor & 0xff00) >> 8;
	const TInt greenFillColor = (aFillColor & 0xff00) >> 8;

	//Get blue color. Equivalent to TRgb::Blue()
	const TInt blueOutlinePenColor = aOutlinePenColor & 0xff;
	const TInt blueShadowColor = aShadowColor & 0xff;
	const TInt blueFillColor = aFillColor & 0xff;

	const TUint32 mask2 = alpha | (alpha << 16);
	while (aDataBuffer < dataBufferPtrLimit)
		{
		index = *aDataBuffer++;
		
		if (255 == FourColorBlendLookup[index][KBackgroundColorIndex])
			{
			//background colour
			//No drawing required so move on to next pixel.
			pixelPtr += pixelPtrInc;
			continue;
			}
		else if (255 == FourColorBlendLookup[index][KFillColorIndex])
			{
			//Use fill colour to draw
			finalColor = aFillColor;
			}
		else if (255 == FourColorBlendLookup[index][KShadowColorIndex])
			{
			//Use shadow colour to draw
			finalColor = aShadowColor;
			}
		else if (255 == FourColorBlendLookup[index][KOutlineColorIndex])
			{
			//Use outline colour to draw
			finalColor = aOutlinePenColor;
			}
		else
			{
			TUint32 backgroundColor = *pixelPtr;
			blendedRedColor =   redOutlinePenColor * FourColorBlendLookup[index][KOutlineColorIndex] + 
						   		redShadowColor * FourColorBlendLookup[index][KShadowColorIndex] +
						  		redFillColor * FourColorBlendLookup[index][KFillColorIndex] + 
						  		((backgroundColor & 0xff0000) >> 16) * FourColorBlendLookup[index][KBackgroundColorIndex];

			blendedGreenColor = greenOutlinePenColor * FourColorBlendLookup[index][KOutlineColorIndex] + 
								greenShadowColor * FourColorBlendLookup[index][KShadowColorIndex] +
								greenFillColor * FourColorBlendLookup[index][KFillColorIndex] + 
								((backgroundColor & 0xff00) >> 8) * FourColorBlendLookup[index][KBackgroundColorIndex];

			blendedBlueColor =  blueOutlinePenColor * FourColorBlendLookup[index][KOutlineColorIndex] + 
								blueShadowColor * FourColorBlendLookup[index][KShadowColorIndex] +
								blueFillColor * FourColorBlendLookup[index][KFillColorIndex] + 
								(backgroundColor & 0xff) * FourColorBlendLookup[index][KBackgroundColorIndex];

			//Equivalent to TRgb::TRgb(TUint32)
			finalColor = ((blendedRedColor&0xFF00) << 8) | (blendedGreenColor&0xFF00) | (blendedBlueColor>>8);
			}

		if (alpha != 0xff)
			{
			TUint32 backgroundColor = *pixelPtr;
			//Draw the final colour
//
			const TUint32 s_rb = finalColor & 0x00FF00FF;
			const TUint32 s_g = (finalColor & 0xFF00) >> 8;
			const TUint32 d_rb = backgroundColor & 0x00FF00FF;
			const TUint32 rb = ((((alpha * ((0x01000100 + s_rb) - d_rb)) >> 8) + d_rb) - mask2) & 0x00FF00FF;

			const TInt d_g = (backgroundColor & 0xFF00) >> 8;
			const TInt g = ((alpha * (s_g - d_g)) >> 8) + d_g;
	
			finalColor = rb | (g<<8);
			}

		*pixelPtr = (finalColor | 0xff000000);
		pixelPtr += pixelPtrInc;
		}
	return KErrNone;
	}