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