mmplugins/imagingplugins/codecs/ICOCodec/ICOCodec.cpp
changeset 0 40261b775718
equal deleted inserted replaced
-1:000000000000 0:40261b775718
       
     1 // Copyright (c) 1999-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 #include <fbs.h>
       
    17 #include "ICOCodec.h"
       
    18 #include "icomaskprocessor.h"
       
    19 
       
    20 
       
    21 // Constants.
       
    22 const TInt KIcoInfoHeaderSize = 40;
       
    23 const TInt KRgbQuadSize = 4;
       
    24 const TInt KFullyOpaque = 0x7FFFFFFF;
       
    25 const TInt KFullyTransparent = 0x00000000;
       
    26 const TUint KBlack = 0xFF000000;
       
    27 const TUint KWhite = 0xFFFFFFFF;
       
    28 
       
    29 
       
    30 // CIcoReadCodec
       
    31 CIcoReadCodec::CIcoReadCodec(TInt aIconHeadersToProcess)
       
    32 	: iIconHeadersToProcess(aIconHeadersToProcess)
       
    33 	{}
       
    34 
       
    35 CIcoReadCodec::~CIcoReadCodec()
       
    36 	{
       
    37 	}
       
    38 
       
    39 CIcoReadCodec* CIcoReadCodec::NewL(TInt aIconHeadersToProcess)
       
    40 {
       
    41 	CIcoReadCodec* self = new(ELeave) CIcoReadCodec(aIconHeadersToProcess);
       
    42 	CleanupStack::PushL(self);
       
    43 	self->ConstructL();
       
    44 	CleanupStack::Pop(self); 
       
    45 	return self;
       
    46 }
       
    47 
       
    48 void CIcoReadCodec::InitFrameHeader(TFrameInfo& aFrameSettings, CFrameImageData& /* aFrameImageData */)
       
    49 	{
       
    50 	ASSERT(aFrameSettings.CurrentFrameState() == TFrameInfo::EFrameInfoUninitialised);
       
    51 	iFrameInfo= &aFrameSettings;
       
    52 	iFrameInfo->SetCurrentFrameState(TFrameInfo::EFrameInfoProcessingFrameHeader);
       
    53 	}
       
    54 
       
    55 TFrameState CIcoReadCodec::ProcessFrameHeaderL(TBufPtr8& aData)
       
    56 	{
       
    57 
       
    58  	if (iFrameInfo->CurrentFrameState() == TFrameInfo::EFrameInfoProcessingFrame)
       
    59 		{
       
    60 		if(aData.Length()>=iImageDataBytes)
       
    61 			{
       
    62 			aData.Shift(iImageDataBytes);
       
    63 			iImageDataBytes = 0;
       
    64 
       
    65 			iFrameInfo->SetCurrentFrameState(TFrameInfo::EFrameInfoProcessingComplete);
       
    66 			if ((--iIconHeadersToProcess) == 0)
       
    67 				return EFrameComplete;
       
    68 			}
       
    69 		else
       
    70 			{
       
    71 			iImageDataBytes -= aData.Length();
       
    72 			aData.Shift(aData.Length()); 
       
    73 			}
       
    74 		}
       
    75 
       
    76 	if (iFrameInfo->CurrentFrameState() == TFrameInfo::EFrameInfoProcessingFrameHeader)
       
    77 		{ // If processing of previous frame info complete or if its the first frame.
       
    78 		if (aData.Length() < KIcoInfoHeaderSize)
       
    79 			User::Leave(KErrUnderflow);
       
    80 
       
    81 		const TUint8* data = STATIC_CAST(const TUint8*, aData.Ptr());
       
    82 				
       
    83 		const TInt width = data[4] + (data[5] << 8) + (data[6] << 16) + (data[7] << 24);
       
    84 		const TInt height = (data[8] + (data[9] << 8) + (data[10] << 16) + (data[11] << 24))/2;
       
    85 				
       
    86 		if(width <= 0 || height <= 0)
       
    87 			User::Leave(KErrCorrupt);		
       
    88 
       
    89 		iFrameInfo->iBitsPerPixel = data[14] + (data[15] << 8);
       
    90 		const TInt colors = 1 << iFrameInfo->iBitsPerPixel;
       
    91 
       
    92 		// Calculate image size. (Pixels)
       
    93 		iFrameInfo->iOverallSizeInPixels.SetSize(width, height);
       
    94 
       
    95 		// Calculate image size. (Bytes)
       
    96 		// XOR image.
       
    97 		iImageDataBytes = (width*iFrameInfo->iBitsPerPixel + 31)/32;
       
    98 		
       
    99 		if(iImageDataBytes <= 0) //overflow
       
   100 			User::Leave(KErrCorrupt);		
       
   101 
       
   102 		// AND image.
       
   103 		iImageDataBytes += (width + 31)/32;
       
   104 		
       
   105 		if(iImageDataBytes <= 0) //overflow
       
   106 			User::Leave(KErrCorrupt);		
       
   107 		
       
   108 		iImageDataBytes *= 4*height;
       
   109 		
       
   110 		if(iImageDataBytes <= 0) //overflow
       
   111 			User::Leave(KErrCorrupt);		
       
   112 
       
   113 		// Include the palette as well.
       
   114 		iImageDataBytes += colors*KRgbQuadSize;
       
   115 		
       
   116 		if(iImageDataBytes <= 0) //overflow
       
   117 			User::Leave(KErrCorrupt);		
       
   118 
       
   119 		iFrameInfo->iFrameCoordsInPixels.SetRect(TPoint(0,0), iFrameInfo->iOverallSizeInPixels);
       
   120 		iFrameInfo->iFrameSizeInTwips.SetSize(0, 0);
       
   121 		iFrameInfo->iDelay = 0;
       
   122 		iFrameInfo->iFlags |= TFrameInfo::ETransparencyPossible | TFrameInfo::EPartialDecodeInvalid;
       
   123 		
       
   124 		if (iFrameInfo->iFrameCoordsInPixels.iBr.iX < 0 || iFrameInfo->iFrameCoordsInPixels.iBr.iY < 0 ||
       
   125 			!(iFrameInfo->iBitsPerPixel == 1 || iFrameInfo->iBitsPerPixel == 4 ||
       
   126 			iFrameInfo->iBitsPerPixel == 8))
       
   127 			User::Leave(KErrCorrupt);
       
   128 
       
   129 		if (iFrameInfo->iBitsPerPixel > 1)
       
   130 			iFrameInfo->iFlags |= TFrameInfo::EColor;
       
   131 
       
   132 		switch (iFrameInfo->iBitsPerPixel)
       
   133 			{
       
   134 			case 1:
       
   135 				iFrameInfo->iFrameDisplayMode = EGray2;
       
   136 				break;
       
   137 
       
   138 			case 4:
       
   139 				iFrameInfo->iFrameDisplayMode = EColor16;
       
   140 				iFrameInfo->iFlags |= TFrameInfo::EColor;
       
   141 				break;
       
   142 
       
   143 			case 8:
       
   144 				iFrameInfo->iFrameDisplayMode = EColor256;
       
   145 				iFrameInfo->iFlags |= TFrameInfo::EColor;
       
   146 				break;
       
   147 			}
       
   148 
       
   149 		aData.Shift(KIcoInfoHeaderSize);
       
   150 		TInt frameDataOffset = iFrameInfo->FrameDataOffset();
       
   151 		iFrameInfo->SetFrameDataOffset(frameDataOffset + KIcoInfoHeaderSize);
       
   152 
       
   153 		iFrameInfo->SetCurrentFrameState(TFrameInfo::EFrameInfoProcessingFrame);
       
   154 		}
       
   155 
       
   156 	return EFrameIncomplete;
       
   157 	}
       
   158 
       
   159 TFrameState CIcoReadCodec::ProcessFrameL(TBufPtr8& aSrc)
       
   160 	{	
       
   161 	if (iNewFrame)
       
   162 		{
       
   163 		// Extract the palette.
       
   164 		TInt colors = 1 << iFrameInfo->iBitsPerPixel;
       
   165 
       
   166 		if (aSrc.Length()<(colors*KRgbQuadSize))
       
   167 			return EFrameIncomplete;
       
   168 
       
   169 		const TUint8* aSrcPtr = aSrc.Ptr();
       
   170 		TInt baseIndex;
       
   171 		for (TInt paletteIndex = 0; paletteIndex < colors; paletteIndex++)
       
   172 			{
       
   173 			baseIndex = KRgbQuadSize*paletteIndex;
       
   174 			iPalette[paletteIndex] = TRgb(aSrcPtr[baseIndex+2],aSrcPtr[baseIndex+1],aSrcPtr[baseIndex]);
       
   175 			}
       
   176 
       
   177 		aSrc.Shift(colors*KRgbQuadSize);
       
   178 
       
   179 		iNewFrame = EFalse;
       
   180 		}
       
   181 
       
   182 	if (aSrc.Length() == 0)
       
   183 		return EFrameIncomplete;
       
   184 
       
   185 	TUint8* srcStart = CONST_CAST(TUint8*,aSrc.Ptr());
       
   186 	iDataPtr = srcStart;
       
   187 	iDataPtrLimit = srcStart + aSrc.Length();
       
   188 
       
   189 	DoProcessL();
       
   190 
       
   191 	TInt bytesUsed = iDataPtr - srcStart;
       
   192 	aSrc.Shift(bytesUsed);
       
   193 
       
   194 	ASSERT(iBmpBytesExpected>=0); // not clear if value can be negative - if it does occur, need to think about it
       
   195 
       
   196 	if (iBmpBytesExpected > 0)
       
   197 		{
       
   198 		const TInt bmpBytesUsed = Min(bytesUsed, iBmpBytesExpected);
       
   199 		iBmpBytesExpected -= bmpBytesUsed;
       
   200 		bytesUsed -= bmpBytesUsed;
       
   201 		}
       
   202 
       
   203 	CImageProcessor*const imageProc = ImageProcessor();
       
   204 	CImageProcessor*const maskProc = MaskProcessor();
       
   205 
       
   206 	if (bytesUsed > 0 && maskProc)
       
   207 		{
       
   208 		const TInt maskBytesUsed = Min(bytesUsed, iMaskBytesExpected);
       
   209 		iMaskBytesExpected -= maskBytesUsed;
       
   210 		}
       
   211 
       
   212 	if ((!maskProc && iBmpBytesExpected <= 0) || (maskProc && iMaskBytesExpected <= 0))
       
   213 		{
       
   214 		imageProc->FlushPixels();
       
   215 		if (maskProc)
       
   216 			maskProc->FlushPixels();
       
   217 
       
   218 		iNewFrame = ETrue;
       
   219 		Pos().SetXY(0,0);
       
   220 		return EFrameComplete;
       
   221 		}
       
   222 
       
   223 	return EFrameIncomplete;
       
   224 	}
       
   225 
       
   226 void CIcoReadCodec::InitFrameL(TFrameInfo& aFrameInfo, CFrameImageData& /*aFrameImageData*/, TBool aDisableErrorDiffusion, CFbsBitmap& aDestination, CFbsBitmap* aDestinationMask)
       
   227 	{
       
   228 
       
   229 	iFrameInfo= &aFrameInfo;
       
   230 	CFbsBitmap& newFrame = aDestination;
       
   231 
       
   232 	TSize& originalSize = iFrameInfo->iOverallSizeInPixels;
       
   233 	Pos().iY = originalSize.iHeight - 1;
       
   234 
       
   235 	const TDisplayMode dispMode = (iFrameInfo->iBitsPerPixel == 1) ? EGray2 : EColor256;
       
   236 	const TSize destinationSize(aDestination.SizeInPixels());
       
   237 	
       
   238 	TInt reductionFactor = ReductionFactor(originalSize, destinationSize);
       
   239 	CImageProcessor* imageProc = ImageProcessorUtility::NewImageProcessorL(aDestination, reductionFactor, dispMode, aDisableErrorDiffusion);
       
   240 	SetImageProcessor(imageProc);
       
   241 	
       
   242 	imageProc->PrepareL(newFrame, originalSize);
       
   243 	imageProc->SetPos(TPoint(0, originalSize.iHeight - 1));
       
   244 	imageProc->SetYPosIncrement(-1);
       
   245 
       
   246 	CImageProcessor* maskProc = NULL;
       
   247 	SetMaskProcessor(NULL);
       
   248 
       
   249 	if (aDestinationMask)
       
   250 		{
       
   251 		CFbsBitmap& newMaskFrame = *aDestinationMask;
       
   252 		maskProc = ImageProcessorUtility::NewImageProcessorL(newMaskFrame, originalSize, EGray2, aDisableErrorDiffusion);
       
   253 		SetMaskProcessor(maskProc);
       
   254 		maskProc->PrepareL(newMaskFrame, originalSize);
       
   255 		}
       
   256 	else if (newFrame.DisplayMode() == EColor16MA)
       
   257 		{
       
   258 		// 16MA dest and no mask - special case
       
   259 		maskProc = CIcoMaskProcessor::NewL(reductionFactor);
       
   260 		SetMaskProcessor(maskProc);
       
   261 		maskProc->PrepareL(newFrame, originalSize); // uses destination bitmap
       
   262 		}
       
   263 	
       
   264 	if(maskProc)
       
   265 		{
       
   266 		maskProc->SetPos(TPoint(0,originalSize.iHeight - 1));
       
   267 		maskProc->SetYPosIncrement(-1);
       
   268 		const TInt maskWidth = (originalSize.iWidth + 31) & ~31; // round up to 32-byte boundary
       
   269 		maskProc->SetPixelPadding(maskWidth - originalSize.iWidth);
       
   270 		iMaskBytesExpected = (maskWidth * originalSize.iHeight) / 8;
       
   271 		}
       
   272 
       
   273 	const TInt actualWidth = (((originalSize.iWidth * iFrameInfo->iBitsPerPixel) + 31) & ~31) / iFrameInfo->iBitsPerPixel; // round up to 32-byte boundary
       
   274 	imageProc->SetPixelPadding(actualWidth - originalSize.iWidth);
       
   275 
       
   276 	iBmpBytesExpected = (actualWidth * originalSize.iHeight * iFrameInfo->iBitsPerPixel) / 8; // bits are packed into bytes
       
   277 
       
   278 	iNewFrame =ETrue;
       
   279 	}
       
   280 	
       
   281 void CIcoReadCodec::DoProcessL()
       
   282 	{
       
   283 	const TUint8* bmpDataPtrLimit = Min(iDataPtrLimit, iDataPtr + iBmpBytesExpected);
       
   284 	CImageProcessor*const imageProc = ImageProcessor();
       
   285 	switch (iFrameInfo->iBitsPerPixel)
       
   286 		{
       
   287 	case 1:
       
   288 		while (iDataPtr < bmpDataPtrLimit)
       
   289 			{
       
   290 			TUint8 value = *iDataPtr++;
       
   291 
       
   292 			// code will compare value with successive masks 0x80, 0x80 etc downto but not including 
       
   293 			for (TUint mask=0x80; mask!=0; mask >>= 1)
       
   294 				imageProc->SetPixel((value & mask) ? iPalette[1] : iPalette[0]);
       
   295 			}
       
   296 		break;
       
   297 	case 4:
       
   298 		while (iDataPtr < bmpDataPtrLimit)
       
   299 			{
       
   300 			TUint8 value = *iDataPtr++;
       
   301 
       
   302 			imageProc->SetPixel(iPalette[value >> 4]);
       
   303 			imageProc->SetPixel(iPalette[value & 0x0f]);
       
   304 			}
       
   305 		break;
       
   306 	case 8:
       
   307 		while (iDataPtr < bmpDataPtrLimit)
       
   308 			imageProc->SetPixel(iPalette[*iDataPtr++]);
       
   309 		break;
       
   310 	default:
       
   311 		User::Leave(KErrCorrupt);
       
   312 		break;
       
   313 		}
       
   314 
       
   315 	CImageProcessor*const maskProc = MaskProcessor();
       
   316 	if (maskProc)
       
   317 		{
       
   318 		// force a flush
       
   319 		imageProc->FlushPixels();
       
   320 						
       
   321 		const TUint8* maskDataPtrLimit = Min(iDataPtrLimit, iDataPtr + iMaskBytesExpected);
       
   322 
       
   323 		while (iDataPtr < maskDataPtrLimit)
       
   324 			{
       
   325 			TUint8 value = *iDataPtr++;
       
   326 
       
   327 			// code will compare value with successive masks 0x80, 0x80 etc downto but not including 
       
   328 			for (TUint mask=0x80; mask!=0; mask >>= 1)
       
   329 				{
       
   330 				maskProc->SetPixel((value & mask) ? TRgb(KBlack, KFullyTransparent) : TRgb(KWhite, KFullyOpaque));				
       
   331 				}
       
   332 			}
       
   333 		}
       
   334 	}