diff -r 000000000000 -r 5d03bc08d59c graphicsdeviceinterface/screendriver/sbit/BMDRAW32A.CPP --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graphicsdeviceinterface/screendriver/sbit/BMDRAW32A.CPP Tue Feb 02 01:47:50 2010 +0200 @@ -0,0 +1,708 @@ +// Copyright (c) 2004-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" + +/** +Performs a blend based on the PD method, with 2* 16 bit in one 32 bit operation optimisation. +Note that this method assumes both input s are NOT alpha pre multiplied, but the output IS pre multiplied. +The mechanism of this method is non-standard and non-intuitive, and is being addressed in 9.3 +by developing distinct classes for the premultiplied and nonmultiplied cases. +The mechanism remains hybrid to maintain compatibility and colour channel overflows caused by rounding +overflows have been addressed. +PD is basically CDest=CSrc*MulSrc+CDest*MulDest +//A second optimisation is that multiplier value must be scaled from 0..255 to 0.0..1.0, this is 1/255 = 0.00392156. +A second optimisation is that multiplier value must be scaled from 257..65535 to 0.0..1.0, this is 1/65535 = 0.0000152590. +This used to be done by simply adding 1, giving 1..256/256 +but this allows overflows to occur when the fractional parts are added together. +We want to keep adding the fractional parts as that gives a better result. +Instead I am now using an approximation of 0.00392151, based on 255*257/256. +To describe it imagine a "decimal" colour mode, where the channels count from 0..9, and 10-based operations are "efficient". +We need 9 to generate 1.0 or 10/10 meaning "all". +If we add 1, then we get 1..10 ==> 0.1 .. 1.0 +If we multiply by 1.1 then we get 0.0 .. 9.9. +And finally add a 0.5 rounding to the result. +I do this multiply after the CSrc*MulSrc, while I still have a 16bit intermediate result. +It is possible to generate a faster, less accurate result by exhaustively finding +the highest value that can be added instead of rb = rb+((rb>>8)&0x00ff00ff)+0x00800080; without causing an overflow. +*/ +FORCEINLINE TUint32 OptimizedBlend32A(TUint32 aBeneath,TUint32 aSrcColor,TUint8 aMaskBuffer) + { + if(aMaskBuffer) + { + if(aMaskBuffer == 0xff) // opaque, so unchanged + { + //Still need to convert source to destination from non-multiplied to pre-multiplied + //But this code resolves to a copy. The ARM optimiser prefers shifts over big constants. + return (aSrcColor|(aMaskBuffer<<24)); + } + else + { + //0, 1, 2, 3 + //b, g, r, alpha + + const TUint32 srcMult = aMaskBuffer; + TUint32 destMult = ((255 - aMaskBuffer) * ((aBeneath >> 24))); + //This gives a slightly more accurate result than ((aBeneath >> 24)+1) + destMult=destMult+(destMult>>8); + destMult+= 0x0080; + destMult >>= 8; + + TUint32 rb =(((aSrcColor&0x00ff00ff)*srcMult)) + (((aBeneath&0x00ff00ff)*destMult)); + rb = rb+((rb>>8)&0x00ff00ff); + rb+=0x00800080; + rb>>=8; + TUint32 ag = (((aSrcColor&0x0000ff00)*srcMult)) + (((aBeneath&0x0000ff00)*destMult)); + ag>>=8; //Note that if alpha is processed here, this shift must be performed before the multiplies + ag = ag+((ag>>8)&0x00ff00ff); + ag+=0x00800080; + TUint32 aa = srcMult+destMult; + return (rb&0x00ff00ff) | (ag&0x0000ff00) | (aa << 24); + + } + } + else // completely transparent + { + return aBeneath; + } + + } + +TInt CDrawThirtyTwoBppBitmapAlpha::Construct(TSize aSize) + { + return Construct(aSize, aSize.iWidth << 2); + } + +TInt CDrawThirtyTwoBppBitmapAlpha::Construct(TSize aSize, TInt aStride) + { + iDispMode = EColor16MA; + return CDrawThirtyTwoBppBitmapCommon::Construct(aSize, aStride); + } + +void CDrawThirtyTwoBppBitmapAlpha::Shadow(TUint32& aColor) + { + TUint32 value = aColor & 0x00ffffff; + if (iShadowMode & EFade) + { +#if defined(SYMBIAN_USE_FAST_FADING) + value = ((value >> 1) & ~0x00808080) + (SYMBIAN_USE_FAST_FADING); +#else + const TInt wordFadeMapOffset = ((iFadeMapOffset & 0xff) << 16) | (iFadeMapOffset & 0xff); + const TInt rb = ((((value & 0x00ff00ff) * iFadeMapFactor) >> 8) + wordFadeMapOffset) & 0x00ff00ff; + const TInt g = ((((value & 0x0000ff00) * iFadeMapFactor) >> 16) + iFadeMapOffset) << 8; + value = rb | g; +#endif + } + + if (iShadowMode & EShadow) + { + const TInt r = (value & 0x00c00000) ? ((value & 0x00ff0000)-0x00400000) : 0; + const TInt g = (value & 0x0000c000) ? ((value & 0x0000ff00)-0x00004000) : 0; + const TInt b = (value & 0x000000c0) ? ((value & 0x000000ff)-0x00000040) : 0; + value = r | g | b; + } + // alpha is unchanged. + aColor = (aColor & 0xff000000) | value; + } + +/** +MAlphaBlend::WriteRgbAlphaLine() implementation. +@see MAlphaBlend::WriteRgbAlphaLine() +*/ +void CDrawThirtyTwoBppBitmapAlpha::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); + const TInt pixelPtrInc = PixelAddressIncrement(); + const TUint8* maskBufferPtrLimit = aMaskBuffer + aLength; + + // The purpose of this conditional is to remove if statements from within the loop + // if shadow mode is not enabled and the UserDispMode is none or EColor16MA + if(!(iShadowMode & (EFade | EShadow)) && (iUserDispMode ==EColor16MA || iUserDispMode == ENone)) + { + while (aMaskBuffer < maskBufferPtrLimit) + { + if(*aMaskBuffer) + { + *pixelPtr = OptimizedBlend32A(*pixelPtr, *((TUint32*)(aRgbBuffer)), *aMaskBuffer); + } + pixelPtr += pixelPtrInc; + aRgbBuffer += 4; + aMaskBuffer++; + } + } + else + { + while (aMaskBuffer < maskBufferPtrLimit) + { + if(*aMaskBuffer) + { + TUint32 srcColor = *((TUint32*)(aRgbBuffer)); + if(aShadowing == MAlphaBlend::EShdwBefore) + { + Shadow(srcColor); + } + + TUint32 pixelClr = 0x0; + + pixelClr = OptimizedBlend32A(*pixelPtr, srcColor, *aMaskBuffer); + + if(aShadowing == MAlphaBlend::EShdwAfter) + { + Shadow(pixelClr); + } + + if(iUserDispMode !=EColor16MA && iUserDispMode != ENone) + { + TInt red = TUint8(pixelClr >> 16); + TInt green = TUint8(pixelClr >> 8); + TInt blue = TUint8(pixelClr); + CDrawBitmap::MapColorToUserDisplayMode(red,green,blue); + pixelClr = (pixelClr&0xff000000) | (red << 16) | (green << 8) | blue; + } + *pixelPtr = pixelClr; + } + pixelPtr += pixelPtrInc; + aRgbBuffer += 4; + aMaskBuffer++; + } + } + } + +void CDrawThirtyTwoBppBitmapAlpha::WriteRgbAlphaMulti(TInt aX,TInt aY,TInt aLength,TRgb aColor,const TUint8* aMaskBuffer) + { + DeOrientate(aX,aY); + TUint32* pixelPtr = PixelAddress(aX,aY); + const TInt pixelPtrInc = PixelAddressIncrement(); + const TUint8* maskBufferPtrLimit = aMaskBuffer + aLength; + + TUint32 srcColor = aColor.Internal(); + if (iShadowMode) + Shadow(srcColor); + + const TInt red = (srcColor & 0x00ff0000) >> 16; + const TInt green = (srcColor & 0x0000ff00) >> 8; + const TInt blue = srcColor & 0x000000ff; + const TInt alpha = srcColor >> 24; + + if (alpha == 255) + { + // the most common case + // source is opaque, so we simply blend it using the mask + while (aMaskBuffer < maskBufferPtrLimit) + { + + *pixelPtr = OptimizedBlend32A(*pixelPtr, srcColor, *aMaskBuffer); + + pixelPtr += pixelPtrInc; + aMaskBuffer++; + } + } + else + { + // pen is semi-transparent, so we must blend using both the mask and pen alpha + while (aMaskBuffer < maskBufferPtrLimit) + { + TUint8* componentPtr = reinterpret_cast (pixelPtr); + const TUint32 srcAlpha = alpha * aMaskBuffer[0]; + const TUint32 srcMult = srcAlpha * 255; + const TUint32 destMult = (255*255 - srcAlpha) * componentPtr[3]; + componentPtr[0] = TUint8(((blue * srcMult) + (componentPtr[0] * destMult)) / (255*255*255)); + componentPtr[1] = TUint8(((green * srcMult) + (componentPtr[1] * destMult)) / (255*255*255)); + componentPtr[2] = TUint8(((red * srcMult) + (componentPtr[2] * destMult)) / (255*255*255)); + componentPtr[3] = TUint8((srcMult + destMult) / (255*255)); + // ie alpha' = srcAlpha + (1-srcAlpha)*destAlpha + + pixelPtr += pixelPtrInc; + aMaskBuffer++; + } + } + } + +void CDrawThirtyTwoBppBitmapAlpha::WriteRgb(TInt aX,TInt aY,TRgb aColor) + { + const TInt sourceAlpha = aColor.Alpha(); + + if(sourceAlpha==255) + { + TUint32* componentPtr = PixelAddress(aX,aY); + *componentPtr=aColor.Internal(); + } + else if (sourceAlpha==0) + { + return; + } + else + { + TUint8* componentPtr = reinterpret_cast (PixelAddress(aX,aY)); + const TUint32 srcMult = sourceAlpha * 255; + const TUint32 destMult = (255 - sourceAlpha) * componentPtr[3]; + componentPtr[0] = TUint8(((aColor.Blue() * srcMult) + (componentPtr[0] * destMult)) / (255*255)); + componentPtr[1] = TUint8(((aColor.Green() * srcMult) + (componentPtr[1] * destMult)) / (255*255)); + componentPtr[2] = TUint8(((aColor.Red() * srcMult) + (componentPtr[2] * destMult)) / (255*255)); + componentPtr[3] = TUint8((srcMult + destMult) / 255); + // ie alpha' = srcAlpha + (1-srcAlpha)*destAlpha + } + } + +void CDrawThirtyTwoBppBitmapAlpha::WriteBinary(TInt aX,TInt aY,TUint32* aBuffer,TInt aLength,TInt aHeight,TRgb aColor) + { + const TInt sourceAlpha = aColor.Alpha(); + if (sourceAlpha==255) + { + CDrawThirtyTwoBppBitmapCommon::WriteBinary(aX,aY,aBuffer,aLength,aHeight,aColor); + return; + } + if (sourceAlpha==0) + return; + + DeOrientate(aX,aY); + + TInt pixelInc; + TInt rowInc; + + switch(iOrientation) + { + case EOrientationNormal: + { + pixelInc = 1; + rowInc = iScanLineWords; + break; + } + case EOrientationRotated90: + { + pixelInc = iScanLineWords; + rowInc = -1; + break; + } + case EOrientationRotated180: + { + pixelInc = -1; + rowInc = -iScanLineWords; + break; + } + default: // EOrientationRotated270 + { + pixelInc = -iScanLineWords; + rowInc = 1; + } + } + + const TUint32* dataLimit = aBuffer + aHeight; + const TUint32 dataMaskLimit = (aLength < 32) ? 1 << aLength : 0; + + TUint32* pixelPtr = PixelAddress(aX,aY); + + const TInt sourceRed = aColor.Red(); + const TInt sourceGreen = aColor.Green(); + const TInt sourceBlue = aColor.Blue(); + + while (aBuffer < dataLimit) + { + TUint32 dataWord = *aBuffer++; + TUint32 dataMask = 1; + TUint32* tempPixelPtr = pixelPtr; + + while (dataMask != dataMaskLimit) + { + if(dataWord & dataMask) + { + TUint8* componentPtr = reinterpret_cast (tempPixelPtr); + const TUint32 srcMult = sourceAlpha * 255; + const TUint32 destMult = (255 - sourceAlpha) * componentPtr[3]; + componentPtr[0] = TUint8(((sourceBlue * srcMult) + (componentPtr[0] * destMult)) / (255*255)); + componentPtr[1] = TUint8(((sourceGreen * srcMult) + (componentPtr[1] * destMult)) / (255*255)); + componentPtr[2] = TUint8(((sourceRed * srcMult) + (componentPtr[2] * destMult)) / (255*255)); + componentPtr[3] = TUint8((srcMult + destMult) / 255); + // ie alpha' = srcAlpha + (1-srcAlpha)*destAlpha + } + + tempPixelPtr += pixelInc; + dataMask <<= 1; + } + + pixelPtr += rowInc; + } + } + +void CDrawThirtyTwoBppBitmapAlpha::WriteBinaryLineVertical(TInt aX,TInt aY,TUint32* aBuffer,TInt aHeight,TRgb aColor,TBool aUp) + { + const TInt sourceAlpha = aColor.Alpha(); + if (sourceAlpha==255) + { + CDrawThirtyTwoBppBitmapCommon::WriteBinaryLineVertical(aX,aY,aBuffer,aHeight,aColor,aUp); + return; + } + if (sourceAlpha==0) + return; + + DeOrientate(aX,aY); + + TInt scanlineWordLength; + + switch(iOrientation) + { + case EOrientationNormal: + scanlineWordLength = iScanLineWords; + break; + case EOrientationRotated90: + scanlineWordLength = -1; + break; + case EOrientationRotated180: + scanlineWordLength = -iScanLineWords; + break; + default: // EOrientationRotated270 + scanlineWordLength = 1; + } + + if (aUp) + scanlineWordLength = -scanlineWordLength; + + TUint32* pixelPtr = PixelAddress(aX,aY); + const TUint32* pixelPtrLimit = pixelPtr + (aHeight * scanlineWordLength); + TUint32 dataWord = *aBuffer; + TUint32 dataMask = 1; + + const TInt sourceRed = aColor.Red(); + const TInt sourceGreen = aColor.Green(); + const TInt sourceBlue = aColor.Blue(); + + while(pixelPtr != pixelPtrLimit) + { + if(!dataMask) + { + dataMask = 1; + aBuffer++; + dataWord = *aBuffer; + } + + if(dataWord & dataMask) + { + TUint8* componentPtr = reinterpret_cast (pixelPtr); + const TUint32 srcMult = sourceAlpha * 255; + const TUint32 destMult = (255 - sourceAlpha) * componentPtr[3]; + componentPtr[0] = TUint8(((sourceBlue * srcMult) + (componentPtr[0] * destMult)) / (255*255)); + componentPtr[1] = TUint8(((sourceGreen * srcMult) + (componentPtr[1] * destMult)) / (255*255)); + componentPtr[2] = TUint8(((sourceRed * srcMult) + (componentPtr[2] * destMult)) / (255*255)); + componentPtr[3] = TUint8((srcMult + destMult) / 255); + // ie alpha' = srcAlpha + (1-srcAlpha)*destAlpha + } + + dataMask <<= 1; + pixelPtr += scanlineWordLength; + } + } + +void CDrawThirtyTwoBppBitmapAlpha::MapBufferToUserDisplayMode(TInt aLength,TUint32* aBuffer) + { + const TUint32* bufferLimit = aBuffer + aLength; + TRgb color; + + switch (iUserDispMode) + { + case EGray2: + while (aBuffer < bufferLimit) + { + color = TRgb::_Color16MA(*aBuffer); + color = TRgb::_Gray2(color._Gray2()); + *aBuffer++ = color._Color16MA(); + } + break; + case EGray4: + while (aBuffer < bufferLimit) + { + color = TRgb::_Color16MA(*aBuffer); + color = TRgb::_Gray4(color._Gray4()); + *aBuffer++ = color._Color16MA(); + } + break; + case EGray16: + while (aBuffer < bufferLimit) + { + color = TRgb::_Color16MA(*aBuffer); + color = TRgb::_Gray16(color._Gray16()); + *aBuffer++ = color._Color16MA(); + } + break; + case EGray256: + while (aBuffer < bufferLimit) + { + color = TRgb::_Color16MA(*aBuffer); + color = TRgb::_Gray256(color._Gray256()); + *aBuffer++ = color._Color16MA(); + } + break; + case EColor16: + while (aBuffer < bufferLimit) + { + color = TRgb::_Color16MA(*aBuffer); + color = TRgb::Color16(color.Color16()); + *aBuffer++ = color._Color16MA(); + } + break; + case EColor256: + while (aBuffer < bufferLimit) + { + color = TRgb::_Color16MA(*aBuffer); + color = TRgb::Color256(color.Color256()); + *aBuffer++ = color._Color16MA(); + } + break; + case EColor4K: + while (aBuffer < bufferLimit) + { + color = TRgb::_Color16MA(*aBuffer); + color = TRgb::_Color4K(color._Color4K()); + *aBuffer++ = color._Color16MA(); + } + break; + case EColor64K: + while (aBuffer < bufferLimit) + { + color = TRgb::_Color16MA(*aBuffer); + color = TRgb::_Color64K(color._Color64K()); + *aBuffer++ = color._Color16MA(); + } + break; + default: + break; + } + } + +void CDrawThirtyTwoBppBitmapAlpha::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 TInt sourceRed = aColor.Red(); + const TInt sourceGreen = aColor.Green(); + const TInt sourceBlue = aColor.Blue(); + TUint srcValue = aColor._Color16MA(); + while (pixelPtr < pixelRowPtrLimit) + { + for (TUint32* tempPixelPtr = pixelPtr; tempPixelPtr < pixelPtrLimit; tempPixelPtr++) + { + // check that the alpha value is not 0xFF + if((*tempPixelPtr & 0xFF000000) ^ 0xFF000000) + { + TUint8* componentPtr = reinterpret_cast (tempPixelPtr); + const TUint32 srcMult = sourceAlpha * 255; + const TUint32 destMult = (255 - sourceAlpha) * componentPtr[3]; + componentPtr[0] = TUint8(((sourceBlue * srcMult) + (componentPtr[0] * destMult)) / (255*255)); + componentPtr[1] = TUint8(((sourceGreen * srcMult) + (componentPtr[1] * destMult)) / (255*255)); + componentPtr[2] = TUint8(((sourceRed * srcMult) + (componentPtr[2] * destMult)) / (255*255)); + componentPtr[3] = TUint8((srcMult + destMult) / 255); + } + else + { + AlphaBlendPixelToDest(srcValue, (TUint8)sourceAlpha, tempPixelPtr); + } + + // ie alpha' = srcAlpha + (1-srcAlpha)*destAlpha + } + + pixelPtr += iScanLineWords; + pixelPtrLimit += iScanLineWords; + } + } + +void CDrawThirtyTwoBppBitmapAlpha::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) + { + *pixelPtr = OptimizedBlend32A(*pixelPtr, *aBuffer, (*aBuffer)>>24); + + aBuffer++; + pixelPtr += pixelPtrInc; + } + } + +TRgb CDrawThirtyTwoBppBitmapAlpha::RgbColor(TUint32 aColor) const + { + return TRgb::_Color16MA(aColor); + } + +TUint32 CDrawThirtyTwoBppBitmapAlpha::Color(const TRgb& aColor) + { + return aColor._Color16MA(); + } + +void CDrawThirtyTwoBppBitmapAlpha::ShadowArea(const TRect& aRect) + { + const TRect rect(DeOrientate(aRect)); + + __ASSERT_DEBUG(rect.iTl.iX>=0 && rect.iBr.iX<=iSize.iWidth,Panic(EScreenDriverPanicOutOfBounds)); + __ASSERT_DEBUG(rect.iTl.iY>=0 && rect.iBr.iY<=iSize.iHeight,Panic(EScreenDriverPanicOutOfBounds)); + + TUint32* pixelPtr = PixelAddress(rect.iTl.iX,rect.iTl.iY); + TUint32* pixelRowPtrLimit = pixelPtr + (rect.Height() * iScanLineWords); + + TUint32* pixelRowPtr = pixelPtr; + TUint32* pixelPtrLimit = pixelPtr + rect.Width(); + + if (iShadowMode & EFade) + { +#if !defined(SYMBIAN_USE_FAST_FADING) + const TInt wordFadeMapOffset = ((iFadeMapOffset & 0xff) << 16) | (iFadeMapOffset & 0xff); +#endif + while (pixelRowPtr < pixelRowPtrLimit) + { + TUint32* tempPixelPtr = pixelRowPtr; + + while (tempPixelPtr < pixelPtrLimit) + { + const TUint32 color = *tempPixelPtr; +#if defined(SYMBIAN_USE_FAST_FADING) + *tempPixelPtr++ = (color & 0xff000000) | ((((color & 0x00ffffff) >> 1) & ~0x00808080) + (SYMBIAN_USE_FAST_FADING)); +#else + const TInt rb = ((((color & 0x00ff00ff) * iFadeMapFactor) >> 8) + wordFadeMapOffset) & 0x00ff00ff; + const TInt g = ((((color & 0x0000ff00) * iFadeMapFactor) >> 16) + iFadeMapOffset) << 8; + *tempPixelPtr++ = (color & 0xff000000) | rb | g; +#endif + } + + pixelRowPtr += iScanLineWords; + pixelPtrLimit += iScanLineWords; + } + } + + if (iShadowMode & EShadow) + { + pixelRowPtr = pixelPtr; + pixelPtrLimit = pixelPtr + rect.Width(); + + while (pixelRowPtr < pixelRowPtrLimit) + { + TUint32* tempPixelPtr = pixelRowPtr; + + while (tempPixelPtr < pixelPtrLimit) + { + const TUint32 color = *tempPixelPtr; + const TInt r = (color & 0x00c00000) ? ((color & 0x00ff0000)-0x00400000) : 0; + const TInt g = (color & 0x0000c000) ? ((color & 0x0000ff00)-0x00004000) : 0; + const TInt b = (color & 0x000000c0) ? ((color & 0x000000ff)-0x00000040) : 0; + *tempPixelPtr++ = (color & 0xff000000) | r | g | b; + } + + pixelRowPtr += iScanLineWords; + pixelPtrLimit += iScanLineWords; + } + } + } + +TInt CDrawThirtyTwoBppBitmapAlpha::WriteRgbOutlineAndShadow(TInt aX, TInt aY, const TInt aLength, + TUint32 aOutlinePenColor, TUint32 aShadowColor, + TUint32 aFillColor, const TUint8* aDataBuffer) + { + 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 TInt alpha = aOutlinePenColor >> 24; + + 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 + { + const TUint32 backgroundColor = *pixelPtr; + + blendedRedColor = (redOutlinePenColor * FourColorBlendLookup[index][KOutlineColorIndex] + + redShadowColor * FourColorBlendLookup[index][KShadowColorIndex] + + redFillColor * FourColorBlendLookup[index][KFillColorIndex] + + ((backgroundColor & 0xff0000) >> 16) * FourColorBlendLookup[index][KBackgroundColorIndex]) >> 8; + + blendedGreenColor = (greenOutlinePenColor * FourColorBlendLookup[index][KOutlineColorIndex] + + greenShadowColor * FourColorBlendLookup[index][KShadowColorIndex] + + greenFillColor * FourColorBlendLookup[index][KFillColorIndex] + + ((backgroundColor & 0xff00) >> 8) * FourColorBlendLookup[index][KBackgroundColorIndex]) >> 8; + + blendedBlueColor = (blueOutlinePenColor * FourColorBlendLookup[index][KOutlineColorIndex] + + blueShadowColor * FourColorBlendLookup[index][KShadowColorIndex] + + blueFillColor * FourColorBlendLookup[index][KFillColorIndex] + + (backgroundColor & 0xff) * FourColorBlendLookup[index][KBackgroundColorIndex]) >> 8; + + finalColor = (blendedRedColor << 16) | (blendedGreenColor << 8) | blendedBlueColor | 0xff000000; + } + *pixelPtr = OptimizedBlend32A(*pixelPtr, finalColor, alpha); + pixelPtr += pixelPtrInc; + } + return KErrNone; + }