mmplugins/imagingplugins/codecs/ICOCodec/ICOCodec.cpp
changeset 0 40261b775718
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mmplugins/imagingplugins/codecs/ICOCodec/ICOCodec.cpp	Tue Feb 02 01:56:55 2010 +0200
@@ -0,0 +1,334 @@
+// Copyright (c) 1999-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 <fbs.h>
+#include "ICOCodec.h"
+#include "icomaskprocessor.h"
+
+
+// Constants.
+const TInt KIcoInfoHeaderSize = 40;
+const TInt KRgbQuadSize = 4;
+const TInt KFullyOpaque = 0x7FFFFFFF;
+const TInt KFullyTransparent = 0x00000000;
+const TUint KBlack = 0xFF000000;
+const TUint KWhite = 0xFFFFFFFF;
+
+
+// CIcoReadCodec
+CIcoReadCodec::CIcoReadCodec(TInt aIconHeadersToProcess)
+	: iIconHeadersToProcess(aIconHeadersToProcess)
+	{}
+
+CIcoReadCodec::~CIcoReadCodec()
+	{
+	}
+
+CIcoReadCodec* CIcoReadCodec::NewL(TInt aIconHeadersToProcess)
+{
+	CIcoReadCodec* self = new(ELeave) CIcoReadCodec(aIconHeadersToProcess);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop(self); 
+	return self;
+}
+
+void CIcoReadCodec::InitFrameHeader(TFrameInfo& aFrameSettings, CFrameImageData& /* aFrameImageData */)
+	{
+	ASSERT(aFrameSettings.CurrentFrameState() == TFrameInfo::EFrameInfoUninitialised);
+	iFrameInfo= &aFrameSettings;
+	iFrameInfo->SetCurrentFrameState(TFrameInfo::EFrameInfoProcessingFrameHeader);
+	}
+
+TFrameState CIcoReadCodec::ProcessFrameHeaderL(TBufPtr8& aData)
+	{
+
+ 	if (iFrameInfo->CurrentFrameState() == TFrameInfo::EFrameInfoProcessingFrame)
+		{
+		if(aData.Length()>=iImageDataBytes)
+			{
+			aData.Shift(iImageDataBytes);
+			iImageDataBytes = 0;
+
+			iFrameInfo->SetCurrentFrameState(TFrameInfo::EFrameInfoProcessingComplete);
+			if ((--iIconHeadersToProcess) == 0)
+				return EFrameComplete;
+			}
+		else
+			{
+			iImageDataBytes -= aData.Length();
+			aData.Shift(aData.Length()); 
+			}
+		}
+
+	if (iFrameInfo->CurrentFrameState() == TFrameInfo::EFrameInfoProcessingFrameHeader)
+		{ // If processing of previous frame info complete or if its the first frame.
+		if (aData.Length() < KIcoInfoHeaderSize)
+			User::Leave(KErrUnderflow);
+
+		const TUint8* data = STATIC_CAST(const TUint8*, aData.Ptr());
+				
+		const TInt width = data[4] + (data[5] << 8) + (data[6] << 16) + (data[7] << 24);
+		const TInt height = (data[8] + (data[9] << 8) + (data[10] << 16) + (data[11] << 24))/2;
+				
+		if(width <= 0 || height <= 0)
+			User::Leave(KErrCorrupt);		
+
+		iFrameInfo->iBitsPerPixel = data[14] + (data[15] << 8);
+		const TInt colors = 1 << iFrameInfo->iBitsPerPixel;
+
+		// Calculate image size. (Pixels)
+		iFrameInfo->iOverallSizeInPixels.SetSize(width, height);
+
+		// Calculate image size. (Bytes)
+		// XOR image.
+		iImageDataBytes = (width*iFrameInfo->iBitsPerPixel + 31)/32;
+		
+		if(iImageDataBytes <= 0) //overflow
+			User::Leave(KErrCorrupt);		
+
+		// AND image.
+		iImageDataBytes += (width + 31)/32;
+		
+		if(iImageDataBytes <= 0) //overflow
+			User::Leave(KErrCorrupt);		
+		
+		iImageDataBytes *= 4*height;
+		
+		if(iImageDataBytes <= 0) //overflow
+			User::Leave(KErrCorrupt);		
+
+		// Include the palette as well.
+		iImageDataBytes += colors*KRgbQuadSize;
+		
+		if(iImageDataBytes <= 0) //overflow
+			User::Leave(KErrCorrupt);		
+
+		iFrameInfo->iFrameCoordsInPixels.SetRect(TPoint(0,0), iFrameInfo->iOverallSizeInPixels);
+		iFrameInfo->iFrameSizeInTwips.SetSize(0, 0);
+		iFrameInfo->iDelay = 0;
+		iFrameInfo->iFlags |= TFrameInfo::ETransparencyPossible | TFrameInfo::EPartialDecodeInvalid;
+		
+		if (iFrameInfo->iFrameCoordsInPixels.iBr.iX < 0 || iFrameInfo->iFrameCoordsInPixels.iBr.iY < 0 ||
+			!(iFrameInfo->iBitsPerPixel == 1 || iFrameInfo->iBitsPerPixel == 4 ||
+			iFrameInfo->iBitsPerPixel == 8))
+			User::Leave(KErrCorrupt);
+
+		if (iFrameInfo->iBitsPerPixel > 1)
+			iFrameInfo->iFlags |= TFrameInfo::EColor;
+
+		switch (iFrameInfo->iBitsPerPixel)
+			{
+			case 1:
+				iFrameInfo->iFrameDisplayMode = EGray2;
+				break;
+
+			case 4:
+				iFrameInfo->iFrameDisplayMode = EColor16;
+				iFrameInfo->iFlags |= TFrameInfo::EColor;
+				break;
+
+			case 8:
+				iFrameInfo->iFrameDisplayMode = EColor256;
+				iFrameInfo->iFlags |= TFrameInfo::EColor;
+				break;
+			}
+
+		aData.Shift(KIcoInfoHeaderSize);
+		TInt frameDataOffset = iFrameInfo->FrameDataOffset();
+		iFrameInfo->SetFrameDataOffset(frameDataOffset + KIcoInfoHeaderSize);
+
+		iFrameInfo->SetCurrentFrameState(TFrameInfo::EFrameInfoProcessingFrame);
+		}
+
+	return EFrameIncomplete;
+	}
+
+TFrameState CIcoReadCodec::ProcessFrameL(TBufPtr8& aSrc)
+	{	
+	if (iNewFrame)
+		{
+		// Extract the palette.
+		TInt colors = 1 << iFrameInfo->iBitsPerPixel;
+
+		if (aSrc.Length()<(colors*KRgbQuadSize))
+			return EFrameIncomplete;
+
+		const TUint8* aSrcPtr = aSrc.Ptr();
+		TInt baseIndex;
+		for (TInt paletteIndex = 0; paletteIndex < colors; paletteIndex++)
+			{
+			baseIndex = KRgbQuadSize*paletteIndex;
+			iPalette[paletteIndex] = TRgb(aSrcPtr[baseIndex+2],aSrcPtr[baseIndex+1],aSrcPtr[baseIndex]);
+			}
+
+		aSrc.Shift(colors*KRgbQuadSize);
+
+		iNewFrame = EFalse;
+		}
+
+	if (aSrc.Length() == 0)
+		return EFrameIncomplete;
+
+	TUint8* srcStart = CONST_CAST(TUint8*,aSrc.Ptr());
+	iDataPtr = srcStart;
+	iDataPtrLimit = srcStart + aSrc.Length();
+
+	DoProcessL();
+
+	TInt bytesUsed = iDataPtr - srcStart;
+	aSrc.Shift(bytesUsed);
+
+	ASSERT(iBmpBytesExpected>=0); // not clear if value can be negative - if it does occur, need to think about it
+
+	if (iBmpBytesExpected > 0)
+		{
+		const TInt bmpBytesUsed = Min(bytesUsed, iBmpBytesExpected);
+		iBmpBytesExpected -= bmpBytesUsed;
+		bytesUsed -= bmpBytesUsed;
+		}
+
+	CImageProcessor*const imageProc = ImageProcessor();
+	CImageProcessor*const maskProc = MaskProcessor();
+
+	if (bytesUsed > 0 && maskProc)
+		{
+		const TInt maskBytesUsed = Min(bytesUsed, iMaskBytesExpected);
+		iMaskBytesExpected -= maskBytesUsed;
+		}
+
+	if ((!maskProc && iBmpBytesExpected <= 0) || (maskProc && iMaskBytesExpected <= 0))
+		{
+		imageProc->FlushPixels();
+		if (maskProc)
+			maskProc->FlushPixels();
+
+		iNewFrame = ETrue;
+		Pos().SetXY(0,0);
+		return EFrameComplete;
+		}
+
+	return EFrameIncomplete;
+	}
+
+void CIcoReadCodec::InitFrameL(TFrameInfo& aFrameInfo, CFrameImageData& /*aFrameImageData*/, TBool aDisableErrorDiffusion, CFbsBitmap& aDestination, CFbsBitmap* aDestinationMask)
+	{
+
+	iFrameInfo= &aFrameInfo;
+	CFbsBitmap& newFrame = aDestination;
+
+	TSize& originalSize = iFrameInfo->iOverallSizeInPixels;
+	Pos().iY = originalSize.iHeight - 1;
+
+	const TDisplayMode dispMode = (iFrameInfo->iBitsPerPixel == 1) ? EGray2 : EColor256;
+	const TSize destinationSize(aDestination.SizeInPixels());
+	
+	TInt reductionFactor = ReductionFactor(originalSize, destinationSize);
+	CImageProcessor* imageProc = ImageProcessorUtility::NewImageProcessorL(aDestination, reductionFactor, dispMode, aDisableErrorDiffusion);
+	SetImageProcessor(imageProc);
+	
+	imageProc->PrepareL(newFrame, originalSize);
+	imageProc->SetPos(TPoint(0, originalSize.iHeight - 1));
+	imageProc->SetYPosIncrement(-1);
+
+	CImageProcessor* maskProc = NULL;
+	SetMaskProcessor(NULL);
+
+	if (aDestinationMask)
+		{
+		CFbsBitmap& newMaskFrame = *aDestinationMask;
+		maskProc = ImageProcessorUtility::NewImageProcessorL(newMaskFrame, originalSize, EGray2, aDisableErrorDiffusion);
+		SetMaskProcessor(maskProc);
+		maskProc->PrepareL(newMaskFrame, originalSize);
+		}
+	else if (newFrame.DisplayMode() == EColor16MA)
+		{
+		// 16MA dest and no mask - special case
+		maskProc = CIcoMaskProcessor::NewL(reductionFactor);
+		SetMaskProcessor(maskProc);
+		maskProc->PrepareL(newFrame, originalSize); // uses destination bitmap
+		}
+	
+	if(maskProc)
+		{
+		maskProc->SetPos(TPoint(0,originalSize.iHeight - 1));
+		maskProc->SetYPosIncrement(-1);
+		const TInt maskWidth = (originalSize.iWidth + 31) & ~31; // round up to 32-byte boundary
+		maskProc->SetPixelPadding(maskWidth - originalSize.iWidth);
+		iMaskBytesExpected = (maskWidth * originalSize.iHeight) / 8;
+		}
+
+	const TInt actualWidth = (((originalSize.iWidth * iFrameInfo->iBitsPerPixel) + 31) & ~31) / iFrameInfo->iBitsPerPixel; // round up to 32-byte boundary
+	imageProc->SetPixelPadding(actualWidth - originalSize.iWidth);
+
+	iBmpBytesExpected = (actualWidth * originalSize.iHeight * iFrameInfo->iBitsPerPixel) / 8; // bits are packed into bytes
+
+	iNewFrame =ETrue;
+	}
+	
+void CIcoReadCodec::DoProcessL()
+	{
+	const TUint8* bmpDataPtrLimit = Min(iDataPtrLimit, iDataPtr + iBmpBytesExpected);
+	CImageProcessor*const imageProc = ImageProcessor();
+	switch (iFrameInfo->iBitsPerPixel)
+		{
+	case 1:
+		while (iDataPtr < bmpDataPtrLimit)
+			{
+			TUint8 value = *iDataPtr++;
+
+			// code will compare value with successive masks 0x80, 0x80 etc downto but not including 
+			for (TUint mask=0x80; mask!=0; mask >>= 1)
+				imageProc->SetPixel((value & mask) ? iPalette[1] : iPalette[0]);
+			}
+		break;
+	case 4:
+		while (iDataPtr < bmpDataPtrLimit)
+			{
+			TUint8 value = *iDataPtr++;
+
+			imageProc->SetPixel(iPalette[value >> 4]);
+			imageProc->SetPixel(iPalette[value & 0x0f]);
+			}
+		break;
+	case 8:
+		while (iDataPtr < bmpDataPtrLimit)
+			imageProc->SetPixel(iPalette[*iDataPtr++]);
+		break;
+	default:
+		User::Leave(KErrCorrupt);
+		break;
+		}
+
+	CImageProcessor*const maskProc = MaskProcessor();
+	if (maskProc)
+		{
+		// force a flush
+		imageProc->FlushPixels();
+						
+		const TUint8* maskDataPtrLimit = Min(iDataPtrLimit, iDataPtr + iMaskBytesExpected);
+
+		while (iDataPtr < maskDataPtrLimit)
+			{
+			TUint8 value = *iDataPtr++;
+
+			// code will compare value with successive masks 0x80, 0x80 etc downto but not including 
+			for (TUint mask=0x80; mask!=0; mask >>= 1)
+				{
+				maskProc->SetPixel((value & mask) ? TRgb(KBlack, KFullyTransparent) : TRgb(KWhite, KFullyOpaque));				
+				}
+			}
+		}
+	}