mmplugins/imagingplugins/codecs/JPEGCodec/JPEGCodec.cpp
changeset 0 40261b775718
child 14 cd271b19d824
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 // CJpgReadCodec::GetHuffmanCodeL() is based heavily on HUFFMAN_DECODE() from jdhuff.h
       
    17 // in the IJG code, Copyright (C) 1991-1997, Thomas G. Lane.
       
    18 /**
       
    19    @file
       
    20    @internalComponent
       
    21 */
       
    22 
       
    23 #include <fbs.h>
       
    24 #include "ImageUtils.h"
       
    25 #include "icl/ImageCodec.h"
       
    26 #include "JpegTypes.h"
       
    27 #include "rawcolorprocessor.h"
       
    28 #include "jpgimageframeprocessor.h"
       
    29 #include "JPEGCodec.h"
       
    30 #include "ImageProcessorPriv.h"
       
    31 #include "fwextconstants.h"
       
    32 #include <imageprocessor/imageprocessor.h>
       
    33 
       
    34 #ifdef JPEG_DEBUG_OUTPUT
       
    35 // This can be turned off in the MMP.
       
    36 #pragma message("Building Debug version of JPEG codec!")
       
    37 #endif
       
    38 
       
    39 const TInt KMaxMCUPerDraw = 100; 	// Maximum MCUs to draw per run
       
    40 // new value should be 48
       
    41 const TInt KMarkerLookAhead=32;		// number of bytes which are checked ahead for presense of 0xFF
       
    42 const TInt KMCUDataLeftThreshhold=192; // approximate value for MCU size, used to avoid re-decoding MCUs when it span data blocks
       
    43 const TInt KMCUMaxTotalDataUnits=1024; // Maximum of data units to use on this process' heap; if we need more, we'll create a local chunk to store them.
       
    44 
       
    45 
       
    46 const TInt KUShiftIdx=0;	// index of U shift factor for MCU de-sampling
       
    47 const TInt KVShiftIdx=1;	// index of V shift factor for MCU de-sampling
       
    48 
       
    49 #if defined(__ARMCC__)
       
    50 #pragma push
       
    51 #pragma thumb
       
    52 #endif
       
    53 
       
    54 // CJpgReadCodec
       
    55 CJpgReadCodec::CJpgReadCodec(const TJpgFrameInfo& aFrameInfo,const TJpgScanInfo& aScanInfo)
       
    56  :	iFrameInfo(aFrameInfo),
       
    57 	iScanInfo(aScanInfo),
       
    58 	iOperation(EDecodeNormal)
       
    59 	{
       
    60 	}
       
    61 
       
    62 
       
    63 CJpgReadCodec::~CJpgReadCodec()
       
    64 	{
       
    65 	for (TInt i = 0; i < KJpgNumberOfComponents; i++)
       
    66 		{
       
    67 		delete[] iComponent[i];
       
    68 		}
       
    69 
       
    70 	delete iImageFrameCodecPtr;
       
    71 	delete iRawColorProcessor;
       
    72 	User::Free(iRgbBuffer);
       
    73 	iRgbBuffer = NULL;
       
    74 	}
       
    75 
       
    76 TFrameState CJpgReadCodec::ProcessFrameL(TBufPtr8& aSrc)
       
    77 	{
       
    78 	iDataPtr = CONST_CAST(TUint8*,aSrc.Ptr());
       
    79 	iDataPtrLimit = iDataPtr + aSrc.Length();
       
    80 	iPreviousDataLeft = iDataPtrLimit - iDataPtr;
       
    81 
       
    82 	TFrameState frameState = EFrameComplete;
       
    83 	TRAPD(err, frameState = DoProcessL());
       
    84 	if (err != KErrNone)
       
    85 		{
       
    86 		if (err == KErrCompletion)
       
    87 			{
       
    88 			RestoreState();
       
    89 			frameState = EFrameIncomplete;
       
    90 			}
       
    91 		else if (err == KErrEof)
       
    92 			{
       
    93 			frameState = EFrameComplete;
       
    94 			}
       
    95 		else
       
    96 			{
       
    97 			JPEG_LEAVE(err, "ProcessFrameL");
       
    98 			}
       
    99 		}
       
   100 
       
   101 	aSrc.Shift(iDataPtr - aSrc.Ptr()); // Shift out used data
       
   102 
       
   103 	return frameState;
       
   104 	}
       
   105 	
       
   106 /**
       
   107   used to configure U,V DCT for high-speed scaling mode
       
   108 */
       
   109 void CJpgReadCodec::ConfigureUVComponentDCT(TInt aCompIdx)
       
   110 	{
       
   111 	switch (iScalingFactor)
       
   112 		{
       
   113 		case -2:
       
   114 			if (iHorzSampleFactor[aCompIdx]==iMaxHorzSampleFactor &&
       
   115 				iVertSampleFactor[aCompIdx]==iMaxVertSampleFactor)
       
   116 				{
       
   117 				iCompConf[aCompIdx].iDCT 			= &iFastHalfDCT;
       
   118 				iCompConf[aCompIdx].iDequantFunc	= &TQTable::FastHalfDeQuantize;
       
   119 				}
       
   120 			break;
       
   121 
       
   122 		case -3:
       
   123 			if (iHorzSampleFactor[aCompIdx]==iMaxHorzSampleFactor &&
       
   124 				iVertSampleFactor[aCompIdx]==iMaxVertSampleFactor)
       
   125 				{
       
   126 				iCompConf[aCompIdx].iDCT 			= &iFastQuarterDCT;
       
   127 				iCompConf[aCompIdx].iDequantFunc	= &TQTable::FastQuarterDeQuantize;
       
   128 				}
       
   129 			else if (iHorzSampleFactor[aCompIdx]*2 == iMaxHorzSampleFactor &&
       
   130 						iVertSampleFactor[aCompIdx]*2 == iMaxVertSampleFactor)
       
   131 				{
       
   132 				iCompConf[aCompIdx].iDCT 			= &iFastHalfDCT;
       
   133 				iCompConf[aCompIdx].iDequantFunc	= &TQTable::FastHalfDeQuantize;
       
   134 				}
       
   135 			break;
       
   136 		default:
       
   137 			{
       
   138 			ASSERT(EFalse);
       
   139 			}
       
   140 		}
       
   141 	}
       
   142 //
       
   143 //
       
   144 //
       
   145 void CJpgReadCodec::InitComponentsL()
       
   146 	{
       
   147 	JPEG_ASSERT(iMaxHorzSampleFactor > 0);
       
   148 	JPEG_ASSERT(iMaxVertSampleFactor > 0);
       
   149 	
       
   150 	for (TInt i = 0; i < iFrameInfo.iNumberOfComponents; i++)
       
   151 		{
       
   152 		iHorzSampleFactor[i] = iFrameInfo.iComponent[i].iHorzSampleFactor;
       
   153 		iVertSampleFactor[i] = iFrameInfo.iComponent[i].iVertSampleFactor;
       
   154 		iHorzSampleRatio[i] = iMaxHorzSampleFactor / iHorzSampleFactor[i];
       
   155 		iVertSampleRatio[i] = iMaxVertSampleFactor / iVertSampleFactor[i];
       
   156 		
       
   157 		TInt dataUnits = iHorzSampleFactor[i] * iVertSampleFactor[i];
       
   158 		iMCUDataUnitCount[i] = dataUnits;
       
   159 		if ((i == 0) || !iMonochrome)
       
   160 			{
       
   161 			JPEG_ASSERT(dataUnits > 0);
       
   162 			delete[] iComponent[i];
       
   163 			iComponent[i] = NULL;
       
   164 			iComponent[i] = new(ELeave) TDataUnit[dataUnits];
       
   165 			}
       
   166 		}
       
   167 	}
       
   168 
       
   169 //
       
   170 //
       
   171 //
       
   172 void CJpgReadCodec::InitFrameL(TFrameInfo& /*aFrameInfo*/, CFrameImageData& /*aFrameImageData*/, TBool aDisableErrorDiffusion, CFbsBitmap& aFrame, CFbsBitmap* /*aFrameMask*/)
       
   173 	{
       
   174 	JPEG_DEBUG1("InitFrameL(TFrameInfo)");
       
   175 	JPEG_DEBUG3(" - iFrameInfo dimensions: %d x %d",
       
   176 			iFrameInfo.iSizeInPixels.iWidth,
       
   177 			iFrameInfo.iSizeInPixels.iHeight);
       
   178 
       
   179 	JPEG_DEBUG3(" - aFrame dimensions: %d x %d",
       
   180 			aFrame.SizeInPixels().iWidth,
       
   181 			aFrame.SizeInPixels().iHeight);
       
   182 
       
   183 	PreInitFrameL();
       
   184 
       
   185 	iMonochrome |= (aFrame.DisplayMode() <= EGray256);
       
   186 
       
   187 	if ((iMaxHorzSampleFactor != iFrameInfo.iComponent[KYComp].iHorzSampleFactor) ||
       
   188 		(iMaxVertSampleFactor != iFrameInfo.iComponent[KYComp].iVertSampleFactor))
       
   189 		{
       
   190 		// Current implementation doesn't support images with Y sampling frequency
       
   191 		// lower than U or V components
       
   192 		JPEG_LEAVE(KErrNotSupported, "Unsupported sampling frequency");
       
   193 		}
       
   194 
       
   195 	InitComponentsL();
       
   196 	for (TInt i = 0; i < iFrameInfo.iNumberOfComponents; i++)
       
   197 		{
       
   198 		if ((iFrameInfo.iComponent[i].iVertSampleFactor == 3) ||
       
   199 			(iFrameInfo.iComponent[i].iHorzSampleFactor == 3))
       
   200 			{
       
   201 			JPEG_LEAVE(KErrCorrupt, "Bad sample factor");
       
   202 			}
       
   203 		
       
   204 		if ((i == 1) || (i == 2))
       
   205 			{
       
   206 			iHorzSampleRatioSh[i - 1] = iHorzSampleRatio[i] / 2;
       
   207 			iVertSampleRatioSh[i - 1] = iVertSampleRatio[i] / 2;
       
   208 			}
       
   209 		}
       
   210 
       
   211 	TSize requiredSize = iFrameInfo.iSizeInPixels;
       
   212 	TInt err = iExtensionManager->GetDestinationSize(requiredSize);
       
   213 	JPEG_LEAVE_IF_ERROR(err, "GetDestinationSize failed");
       
   214 	
       
   215 	if (iExtensionManager->ScalerExtensionRequested())
       
   216 		{
       
   217 		// Explicit scaling
       
   218 		// Mandatory check that the destination size matches the calculated size
       
   219 		if (requiredSize != aFrame.SizeInPixels())
       
   220 			{
       
   221 			JPEG_LEAVE(KErrArgument, "Destination bitmap size != GetDestinationSize");
       
   222 			}
       
   223 		
       
   224 		TSize sizeToScale = iExtensionManager->ClippingRectExtensionRequested() ?
       
   225 							iExtensionManager->ClippingRect().Size() : iFrameInfo.iSizeInPixels;
       
   226 		
       
   227 		if (iExtensionManager->DimensionsSwapped())
       
   228 			{
       
   229 			sizeToScale.SetSize(sizeToScale.iHeight, sizeToScale.iWidth);
       
   230 			}
       
   231 		
       
   232 		err = iExtensionManager->GetScalingCoefficient(iScalingFactor, &sizeToScale);
       
   233 		JPEG_LEAVE_IF_ERROR(err, "GetScalingCoefficient failed");
       
   234 			
       
   235 		if (iScalingFactor != -4)
       
   236 			{
       
   237 			if (!iHighSpeedMode || (iHighSpeedMode && iMonochrome))
       
   238 				{
       
   239 				// Needs to be the original image/cropped size in correct orientation
       
   240 				// and NOT the GetDestinationSize() value
       
   241 				requiredSize = sizeToScale;	
       
   242 				}
       
   243 			}
       
   244 		}
       
   245 	else
       
   246 		{
       
   247 		// Implicit scaling for compatibility
       
   248 		// requiredSize now equals full, cropped or scaled in correct orientation
       
   249 		iScalingFactor = ScalingCoefficient(requiredSize, aFrame.SizeInPixels());
       
   250 		if ((iHighSpeedMode && !iMonochrome) || iScalingFactor == -4)
       
   251 			{
       
   252 			err = GetReducedSize(requiredSize, iScalingFactor, requiredSize);
       
   253 			JPEG_LEAVE_IF_ERROR(err, "GetReducedSize failed");
       
   254 			}
       
   255 		}
       
   256 	
       
   257 	if (iScalingFactor == 1)
       
   258 		{
       
   259 		// For convenience
       
   260 		iScalingFactor = -iScalingFactor;
       
   261 		}
       
   262 	
       
   263 	JPEG_DEBUG2(" - iMonochrome = %d", iMonochrome);
       
   264 	JPEG_DEBUG2(" - iProgressive = %d", iProgressive);
       
   265 	JPEG_DEBUG2(" - iHighSpeedMode = %d", iHighSpeedMode);
       
   266 	JPEG_DEBUG2(" - iScalingFactor = %d", iScalingFactor);
       
   267 
       
   268 	// "raw" processor is used when we can directly write data in output format rather than TRgb
       
   269 	// that provides with saving on "to/from" TRgb conversion and memory bandwidth
       
   270 	TBool useRawProc = (!iMonochrome && !iProgressive &&
       
   271 										(aFrame.DisplayMode() == EColor16M ||
       
   272 										(aFrame.DisplayMode() == EColor64K &&
       
   273 										 CPluginExtensionManager::ConvertScalingCoeffToReductionFactor(iScalingFactor) == 3))
       
   274 						);
       
   275 
       
   276 	// defaults which are equal to legacy behaviour
       
   277 	iMcuWriteFunc = (iMonochrome ? &CJpgReadCodec::WriteMonoMCU : &CJpgReadCodec::WriteUnScaledMCU);
       
   278 
       
   279 	iCompConf[KYComp].iDequantFunc = &TQTable::DeQuantize;
       
   280 	iCompConf[KUComp].iDequantFunc = &TQTable::DeQuantize;
       
   281 	iCompConf[KVComp].iDequantFunc = &TQTable::DeQuantize;
       
   282 
       
   283 	TInt reductionFactor = 0;
       
   284 	switch (iScalingFactor)
       
   285 		{
       
   286 		case -1:
       
   287 			reductionFactor = 0;
       
   288 			iCompConf[KYComp].iDCT = &iFullDCT;
       
   289 			iCompConf[KUComp].iDCT = &iFullDCT;
       
   290 			iCompConf[KVComp].iDCT = &iFullDCT;
       
   291 
       
   292 			if (iMonochrome)
       
   293 				{
       
   294 				iMcuWriteFunc = &CJpgReadCodec::WriteMonoMCU;
       
   295 				JPEG_DEBUG1(" - Using Mono function");
       
   296 				}
       
   297 			else
       
   298 				{
       
   299 				if (useRawProc)
       
   300 					{
       
   301 					iMcuWriteFunc = &CJpgReadCodec::WriteUnScaledMCU16M;
       
   302 					}
       
   303 				else
       
   304 					{
       
   305 					iMcuWriteFunc = &CJpgReadCodec::WriteUnScaledMCU;
       
   306 					}
       
   307 				JPEG_DEBUG1(" - Using Unscaled functions");
       
   308 				}
       
   309 			break;
       
   310 
       
   311 		case -2:
       
   312 			reductionFactor = 1;
       
   313 			iCompConf[KYComp].iDCT = &iHalfDCT;
       
   314 			iCompConf[KUComp].iDCT = &iHalfDCT;
       
   315 			iCompConf[KVComp].iDCT = &iHalfDCT;
       
   316 			if (!iMonochrome && iHighSpeedMode) // we do not support fast scaling for monochrome
       
   317 				{
       
   318 				reductionFactor = 0;
       
   319 				if (useRawProc)
       
   320 					{
       
   321 					iMcuWriteFunc = &CJpgReadCodec::WriteDiv2ScaledMCU16M;
       
   322 					}
       
   323 				else
       
   324 					{
       
   325 					iMcuWriteFunc = &CJpgReadCodec::WriteDiv2ScaledMCU;
       
   326 					}
       
   327 				JPEG_DEBUG1(" - Using Div2 functions");
       
   328 
       
   329 				iCompConf[KYComp].iDCT 			= &iFastHalfDCT;
       
   330 				iCompConf[KYComp].iDequantFunc	= &TQTable::FastHalfDeQuantize;
       
   331 				ConfigureUVComponentDCT(KUComp);
       
   332 				ConfigureUVComponentDCT(KVComp);
       
   333 				}
       
   334 			else
       
   335 				{
       
   336 				iScalingFactor = -1;
       
   337 				useRawProc = EFalse;
       
   338 				}
       
   339 			break;
       
   340 
       
   341 		case -3:
       
   342 			reductionFactor = 2;
       
   343 			iCompConf[KYComp].iDCT = &iQuarterDCT;
       
   344 			iCompConf[KUComp].iDCT = &iQuarterDCT;
       
   345 			iCompConf[KVComp].iDCT = &iQuarterDCT;
       
   346 			if (!iMonochrome && iHighSpeedMode) // we do not support fast scaling for monochrome
       
   347 				{
       
   348 				reductionFactor = 0;
       
   349 				if (useRawProc)
       
   350 					{
       
   351 					iMcuWriteFunc = &CJpgReadCodec::WriteDiv4ScaledMCU16M;
       
   352 					}
       
   353 				else
       
   354 					{
       
   355 					iMcuWriteFunc = &CJpgReadCodec::WriteDiv4ScaledMCU;
       
   356 					}
       
   357 				JPEG_DEBUG1(" - Using Div4 functions");
       
   358 
       
   359 				iCompConf[KYComp].iDCT = &iFastQuarterDCT;
       
   360 				iCompConf[KYComp].iDequantFunc = &TQTable::FastQuarterDeQuantize;
       
   361 				ConfigureUVComponentDCT(KUComp);
       
   362 				ConfigureUVComponentDCT(KVComp);
       
   363 				}
       
   364 			else
       
   365 				{
       
   366 				iScalingFactor = -1;
       
   367 				useRawProc = EFalse;
       
   368 				}
       
   369 			break;
       
   370 
       
   371 		case -4:
       
   372 			iCompConf[KYComp].iDCT = &iEighthDCT;
       
   373 			iCompConf[KUComp].iDCT = &iEighthDCT;
       
   374 			iCompConf[KVComp].iDCT = &iEighthDCT;
       
   375 			iCompConf[KYComp].iDequantFunc = &TQTable::Fast18DeQuantize;
       
   376 			iCompConf[KUComp].iDequantFunc = &TQTable::Fast18DeQuantize;
       
   377 			iCompConf[KVComp].iDequantFunc = &TQTable::Fast18DeQuantize;
       
   378 			reductionFactor = 0;
       
   379 			if (!iMonochrome) // 1/8 Mono has got its own fast 1/8 inside the function
       
   380 				{
       
   381 				iMcuWriteFunc = useRawProc? (aFrame.DisplayMode()==EColor16M ? &CJpgReadCodec::WriteDiv8ScaledMCU16M : &CJpgReadCodec::WriteDiv8ScaledMCU64K)
       
   382 											: &CJpgReadCodec::WriteDiv8ScaledMCU;
       
   383 				JPEG_DEBUG1(" - Using Div8 functions");
       
   384 				}
       
   385 			break;
       
   386 
       
   387 		default:
       
   388 			JPEG_LEAVE(KErrArgument, "Bad scaling factor");
       
   389 			break;
       
   390 		}
       
   391 
       
   392 	iCompConf[KYComp].iDCT->SetPrecision(iFrameInfo.iSamplePrecision);
       
   393 	iCompConf[KUComp].iDCT->SetPrecision(iFrameInfo.iSamplePrecision);
       
   394 	iCompConf[KVComp].iDCT->SetPrecision(iFrameInfo.iSamplePrecision);
       
   395 
       
   396 	if (!iMonochrome)
       
   397 		{
       
   398 		CalculateRgbIndeces();
       
   399 		}
       
   400 
       
   401 	if (iProgressive)
       
   402 		{
       
   403 		iFrameInfo.iMCUBlocksPerLine = 1;
       
   404 		}
       
   405 	else
       
   406 		{
       
   407 		TInt mcuWidth = iFrameInfo.MCUWidthInPixels();
       
   408 		iFrameInfo.iMCUBlocksPerLine = (iFrameInfo.iSizeInPixels.iWidth + mcuWidth - 1) / mcuWidth;
       
   409 		}
       
   410 
       
   411 	// Allocate the intermediate buffer.
       
   412 	iPixelSize = useRawProc ? TDisplayModeUtils::NumDisplayModeBitsPerPixel(aFrame.DisplayMode()) / 8 : sizeof(TRgb);
       
   413 
       
   414 	TInt scaleDivisor = CJpgReadCodec::ScaleFactorToDivisorL(iScalingFactor);
       
   415 	ConfigureAndAllocateBufferL(scaleDivisor);
       
   416 
       
   417 	CImageProcessorExtension* imageProc = NULL;
       
   418 	if (useRawProc)
       
   419 		{
       
   420 		JPEG_DEBUG1(" - Using raw processor");
       
   421 		imageProc = CRawColorProcessor::NewL();
       
   422 		}
       
   423 	else
       
   424 		{
       
   425 		JPEG_DEBUG2(" - Using stock processor, reductionFactor=%d", reductionFactor);
       
   426 		imageProc = ImageProcessorUtility::NewImageProcessorExtensionL(
       
   427 						aFrame,
       
   428 						reductionFactor,
       
   429 						iMonochrome ? EGray256 : ERgb,
       
   430 						aDisableErrorDiffusion || iHighSpeedMode);
       
   431 		}
       
   432 	
       
   433 	ConfigureImageProcessorL(imageProc, aFrame, scaleDivisor, requiredSize);	
       
   434 	CalculateRenderingParams(scaleDivisor);
       
   435 	PostInitFrameL();
       
   436 	}
       
   437 
       
   438 //
       
   439 // Configures the image processor that has been created.
       
   440 // This function does not take ownership of the image processor.
       
   441 //
       
   442 void CJpgReadCodec::ConfigureImageProcessorL(CImageProcessorExtension* aImageProc, CFbsBitmap& aFrame, const TInt aScaleDivisor, const TSize& aPrepareLSize)
       
   443 	{
       
   444 	JPEG_DEBUG2("ConfigureImageProcessorL(aScaleDivisor=%d)", aScaleDivisor);
       
   445 	JPEG_ASSERT(aImageProc);
       
   446 	JPEG_ASSERT(iExtensionManager);
       
   447 	JPEG_ASSERT(aScaleDivisor > 0);
       
   448 	JPEG_ASSERT(aPrepareLSize.iWidth > 0);
       
   449 	JPEG_ASSERT(aPrepareLSize.iHeight > 0);
       
   450 	
       
   451 
       
   452 #ifdef JPEG_DEBUG_OUTPUT
       
   453 	TRAPD(err, iExtensionManager->TransferExtensionDataL(aImageProc));
       
   454 	JPEG_LEAVE_IF_ERROR(err, "TransferExtensionDataL");
       
   455 #else
       
   456 	iExtensionManager->TransferExtensionDataL(aImageProc);
       
   457 #endif
       
   458 
       
   459 	SetImageProcessor(aImageProc);
       
   460 
       
   461 	// Set the padding variables.
       
   462 	TRect clip = iExtensionManager->ClippingRect();
       
   463 	TInt left = (clip.iTl.iX - iMCUClipRect.iTl.iX) / aScaleDivisor;
       
   464 	TInt top = (clip.iTl.iY - iMCUClipRect.iTl.iY) / aScaleDivisor;
       
   465 	TInt bottom = (iMCUClipRect.iBr.iY - clip.iBr.iY) / aScaleDivisor;
       
   466 	TInt right = (iMCUClipRect.iBr.iX - clip.iBr.iX) / aScaleDivisor;
       
   467 
       
   468 	JPEG_DEBUG1(" - clipping rect offsets (scaled):");
       
   469 	JPEG_DEBUG2(" -   top: %d", top);
       
   470 	JPEG_DEBUG2(" -   left: %d", left);
       
   471 	JPEG_DEBUG2(" -   bottom: %d", bottom);
       
   472 	JPEG_DEBUG2(" -   right: %d", right);	
       
   473 	JPEG_DEBUG3(" - Output size: %d x %d", aPrepareLSize.iWidth, aPrepareLSize.iHeight);
       
   474 	
       
   475 	//TBool bottomUp = ETrue;
       
   476 	TInt initialPadding = 0;
       
   477 	TInt padding = 0;
       
   478 
       
   479 	// iRubbish is only valid for non-clipped images.
       
   480 	switch (iOperation)
       
   481 		{
       
   482 		case EDecodeNormal:
       
   483 		case EDecodeHorizontalFlip:
       
   484 			initialPadding = (iUseClipRect ? top : 0);
       
   485 			padding = (iUseClipRect ? left : 0);
       
   486 			break;
       
   487 
       
   488 		case EDecodeVerticalFlip:
       
   489 		case EDecodeRotate180:
       
   490 			initialPadding = (iUseClipRect ? top : 0);
       
   491 			padding = (iUseClipRect ? right : iRubbish.iWidth);
       
   492 			break;
       
   493 
       
   494 		case EDecodeRotate90:
       
   495 		case EDecodeVerticalFlipRotate90:
       
   496 			initialPadding = (iUseClipRect ? left : 0);
       
   497 			padding = (iUseClipRect ? bottom : iRubbish.iHeight);
       
   498 			break;
       
   499 
       
   500 		case EDecodeHorizontalFlipRotate90:
       
   501 		case EDecodeRotate270:
       
   502 			initialPadding = (iUseClipRect ? left : 0);
       
   503 			padding = (iUseClipRect ? top : 0);
       
   504 			break;
       
   505 
       
   506 		default:
       
   507 			ASSERT(EFalse);
       
   508 		}
       
   509 
       
   510 	JPEG_DEBUG2(" - initialPadding = %d", initialPadding);
       
   511 	JPEG_DEBUG2(" - padding = %d", padding);
       
   512 
       
   513 	JPEG_ASSERT(aImageProc);
       
   514 
       
   515 	aImageProc->SetInitialScanlineSkipPadding(initialPadding);
       
   516 	aImageProc->SetPixelPadding(padding);
       
   517 	aImageProc->PrepareL(aFrame, aPrepareLSize, iBufSize);
       
   518 	}
       
   519 
       
   520 //
       
   521 //
       
   522 //
       
   523 TInt CJpgReadCodec::ScaleFactorToDivisorL(TInt aScalingFactor)
       
   524 	{
       
   525 	switch (aScalingFactor)
       
   526 		{
       
   527 		case 1:
       
   528 		case -1:
       
   529 			return 1;
       
   530 
       
   531 		case -2:
       
   532 			return 2;
       
   533 
       
   534 		case -3:
       
   535 			return 4;
       
   536 
       
   537 		case -4:
       
   538 			return 8;
       
   539 
       
   540 		default:
       
   541 			break;
       
   542 		}
       
   543 
       
   544 	// Keep the compiler happy.
       
   545 	JPEG_LEAVE(KErrArgument, "Bad scaling factor");
       
   546 	return 0;
       
   547 	}
       
   548 
       
   549 //
       
   550 // Calculates the necessary intermediate buffer size and allocates it.
       
   551 // It also sets how many MCUs are contained in the buffer (iMCUsPerBuffer).
       
   552 //
       
   553 void CJpgReadCodec::ConfigureAndAllocateBufferL(const TInt aScale)
       
   554 	{
       
   555 	JPEG_DEBUG2("ConfigureAndAllocateBufferL(aScale=%d)", aScale);
       
   556 	JPEG_ASSERT(aScale > 0);
       
   557 
       
   558 	TInt horizMCUs = 0;
       
   559 	TInt vertMCUs = 0;
       
   560 
       
   561 	if (iUseClipRect)
       
   562 		{
       
   563 		// We need to translate the clipping rect from pixels to MCU space.
       
   564 		// Clipping is done before any rotation.
       
   565 		JPEG_ASSERT(!iProgressive);
       
   566 
       
   567 		CalculateMCUBoundingRectL(iFrameInfo.iMCUBlocksPerLine);
       
   568 		horizMCUs = iMCUClipRect.Width() / iFrameInfo.MCUWidthInPixels();
       
   569 		vertMCUs = iMCUClipRect.Height() / iFrameInfo.MCUHeightInPixels();
       
   570 		}
       
   571 	else
       
   572 		{
       
   573 		if (iProgressive)
       
   574 			{
       
   575 			JPEG_ASSERT(aScale == 1);
       
   576 			JPEG_ASSERT(iOperation == EDecodeNormal);
       
   577 
       
   578 			horizMCUs = 1;
       
   579 			vertMCUs = 1;
       
   580 			}
       
   581 		else
       
   582 			{
       
   583 			horizMCUs = iFrameInfo.iMCUBlocksPerLine;
       
   584 			vertMCUs = iFrameInfo.iMCUBlocksPerColumn;
       
   585 
       
   586 			iRubbish.iWidth = ((horizMCUs * iFrameInfo.MCUWidthInPixels()) - iFrameInfo.iSizeInPixels.iWidth) / aScale;
       
   587 			iRubbish.iHeight = ((vertMCUs * iFrameInfo.MCUHeightInPixels()) - iFrameInfo.iSizeInPixels.iHeight) / aScale;
       
   588 
       
   589 			JPEG_DEBUG3(" - iRubbish: %d x %d (scaled)", iRubbish.iWidth, iRubbish.iHeight);
       
   590 			JPEG_ASSERT(iRubbish.iWidth >= 0);
       
   591 			JPEG_ASSERT(iRubbish.iHeight >= 0);
       
   592 			}
       
   593 		}
       
   594 
       
   595 	// We may need to swap dimensions for some rotates.
       
   596 	switch (iOperation)
       
   597 		{
       
   598 		case EDecodeRotate90:
       
   599 		case EDecodeRotate270:
       
   600 		case EDecodeHorizontalFlipRotate90:
       
   601 		case EDecodeVerticalFlipRotate90:
       
   602 			iMCUsPerBuffer = vertMCUs;
       
   603 			iBufSize.iWidth = vertMCUs * iFrameInfo.MCUHeightInPixels();
       
   604 			iBufSize.iHeight = iFrameInfo.MCUWidthInPixels();
       
   605 			break;
       
   606 
       
   607 		default:
       
   608 			iMCUsPerBuffer = horizMCUs;
       
   609 			iBufSize.iWidth = horizMCUs * iFrameInfo.MCUWidthInPixels();
       
   610 			iBufSize.iHeight = iFrameInfo.MCUHeightInPixels();
       
   611 		}
       
   612 
       
   613 	iBufSize.iWidth /= aScale;
       
   614 	iBufSize.iHeight /= aScale;
       
   615 
       
   616 	// Because JPEG doesn't round up with scaling it is possible to have a scaled image that 0x0 in size.
       
   617 	// Things are ok for now because a 1x1 image is actually an 8x8 image and the maximum reduction factor
       
   618 	// supported is -4 (divide by 8). It is possible that larger reduction factors will be supported in
       
   619 	// the future as cameras take larger pictures. In this case an 8x8 image will scale to 0x0.
       
   620 	JPEG_DEBUG3(" - scaled buffer dimensions: %d x %d", iBufSize.iWidth, iBufSize.iHeight);
       
   621 	JPEG_ASSERT(iBufSize.iWidth > 0);
       
   622 	JPEG_ASSERT(iBufSize.iHeight > 0);
       
   623 	JPEG_ASSERT(iPixelSize > 0);
       
   624 
       
   625 	TInt bufSize = iBufSize.iWidth * iBufSize.iHeight * iPixelSize;
       
   626 
       
   627 	User::Free(iRgbBuffer);
       
   628 	iRgbBuffer = NULL;
       
   629 	iRgbBuffer = reinterpret_cast<TRgb*>(User::AllocL(bufSize));
       
   630 	}
       
   631 
       
   632 
       
   633 //
       
   634 // Sets up the fields that control where the pixels are
       
   635 // drawn into the intermediate buffer.
       
   636 //
       
   637 void CJpgReadCodec::CalculateRenderingParams(const TInt aScale)
       
   638 	{
       
   639 	JPEG_DEBUG1("CalculateRenderingParams()");
       
   640 
       
   641 	JPEG_ASSERT(aScale > 0);
       
   642 
       
   643 	TInt mcuPixelWidth = iFrameInfo.MCUWidthInPixels() / aScale;
       
   644 	TInt mcuPixelHeight = iFrameInfo.MCUHeightInPixels() / aScale;
       
   645 
       
   646 	switch (iOperation)
       
   647 		{
       
   648 		case EDecodeNormal:
       
   649 		case EDecodeHorizontalFlip:
       
   650 			// These are the same except FlipHorizontal will draw from bottom up.
       
   651 			iFirstPixelOffset = 0;
       
   652 			iPixelIncrement = 1;
       
   653 			iRgbBufNextLineOffs = iBufSize.iWidth - mcuPixelWidth;
       
   654 			iFillBufferBackwards = EFalse;
       
   655 			iMCUHorizExtent = mcuPixelWidth;
       
   656 			break;
       
   657 
       
   658 		case EDecodeVerticalFlip:
       
   659 		case EDecodeRotate180:
       
   660 			iFirstPixelOffset = mcuPixelWidth - 1;
       
   661 			iPixelIncrement = -1;
       
   662 			iRgbBufNextLineOffs = iBufSize.iWidth + mcuPixelWidth;
       
   663 			iFillBufferBackwards = ETrue;
       
   664 			iMCUHorizExtent = mcuPixelWidth;
       
   665 			break;
       
   666 
       
   667 		case EDecodeRotate90:
       
   668 		case EDecodeVerticalFlipRotate90:
       
   669 			// These differ only in the direction the buffer is copied to the bitmap.
       
   670 			iFirstPixelOffset = mcuPixelHeight - 1;
       
   671 			iPixelIncrement = iBufSize.iWidth;
       
   672 			iRgbBufNextLineOffs = -((iBufSize.iWidth * mcuPixelWidth) + 1);
       
   673 			iFillBufferBackwards = ETrue;
       
   674 			iMCUHorizExtent = mcuPixelHeight;
       
   675 			break;
       
   676 
       
   677 		case EDecodeRotate270:
       
   678 		case EDecodeHorizontalFlipRotate90:
       
   679 			// These differ only in the direction the buffer is copied to the bitmap.
       
   680 			iFirstPixelOffset = 0;
       
   681 			iPixelIncrement = iBufSize.iWidth;
       
   682 			iRgbBufNextLineOffs = -(iBufSize.iWidth * mcuPixelWidth) + 1;
       
   683 			iFillBufferBackwards = EFalse;
       
   684 			iMCUHorizExtent = mcuPixelHeight;
       
   685 			break;
       
   686 
       
   687 		default:
       
   688 			// Bad operation.
       
   689 			ASSERT(EFalse);
       
   690 		}
       
   691 
       
   692 	JPEG_DEBUG2(" - iFirstPixelOffset = %d", iFirstPixelOffset);
       
   693 	JPEG_DEBUG2(" - iPixelIncrement = %d", iPixelIncrement);
       
   694 	JPEG_DEBUG2(" - iRgbBufNextLineOffs = %d", iRgbBufNextLineOffs);
       
   695 	JPEG_DEBUG2(" - iFillBufferBackwards = %d", iFillBufferBackwards);
       
   696 	JPEG_DEBUG2(" - iMCUHorizExtent = %d", iMCUHorizExtent);
       
   697 	}
       
   698 
       
   699 //
       
   700 // This is called when a clipping rectangle has been set.
       
   701 // Subclasses that support clipping must provide a way of
       
   702 // mapping the clip rect pixel coordinates to MCUs.
       
   703 //
       
   704 void CJpgReadCodec::CalculateMCUBoundingRectL(TInt /*aMCUsPerLine*/)
       
   705 	{
       
   706 	JPEG_LEAVE(KErrNotSupported, "CalculateMCUBoundingRectL");
       
   707 	}
       
   708 
       
   709 /**
       
   710    we would go across the whole block top-to-bottom left-to-right
       
   711 */
       
   712 void CJpgReadCodec::CalculateRgbIndeces()
       
   713 	{
       
   714 	TUVidxElemType* pixIdxPtr=iUVIndeces;
       
   715 
       
   716 	TUint offsMask=iMaxVertSampleFactor*iMaxHorzSampleFactor*KJpgDCTBlockSize -1;
       
   717 	TInt vertStep=1;
       
   718 
       
   719 	switch (iScalingFactor)
       
   720 		{
       
   721 		case -4:
       
   722 			offsMask &= ~TUint(KJpgDCTBlockSize - 1);
       
   723 			break;
       
   724 
       
   725 		case -3:
       
   726 			vertStep = 4;
       
   727 			break;
       
   728 
       
   729 		case -2:
       
   730 			vertStep = 2;
       
   731 			break;
       
   732 
       
   733 		default:
       
   734 			ASSERT((iScalingFactor == 1) || (iScalingFactor == -1));
       
   735 		}
       
   736 
       
   737 	for (TInt j = 0; j < iMaxVertSampleFactor*KJpgDCTBlockWidth; j+=vertStep)
       
   738 		{
       
   739 
       
   740 		for (TInt i = 0; i < iMaxHorzSampleFactor; i++)
       
   741 			{
       
   742 			for (TInt k=0; k<2; ++k)
       
   743 				{
       
   744 				const TInt shiftIdx=k;
       
   745 				const TInt comp=k+1;
       
   746 				TInt hOffs		=((i*KJpgDCTBlockWidth)>>iHorzSampleRatioSh[shiftIdx])&7;
       
   747 				TInt hBlkOffs	=(i>>iHorzSampleRatioSh[shiftIdx]) *KJpgDCTBlockSize;
       
   748 
       
   749 				TInt vOffs		=((j>>iVertSampleRatioSh[shiftIdx]&7))*KJpgDCTBlockWidth;
       
   750 
       
   751 				TInt vBlkOffs	=((j/KJpgDCTBlockWidth) >>iVertSampleRatioSh[shiftIdx]) *KJpgDCTBlockSize*iHorzSampleFactor[comp];
       
   752 
       
   753 				*pixIdxPtr++ =  offsMask & (hOffs+  hBlkOffs + vOffs + vBlkOffs);
       
   754 				}
       
   755 
       
   756 			if (iScalingFactor == -3)
       
   757 				{
       
   758 				// for this factor we have 1 more entry per horizontal line
       
   759 				// which is offset against previous pixel i.e. (4>>iHorzSampleRatioSh[Comp])
       
   760 				*pixIdxPtr++ = vertStep>>iHorzSampleRatioSh[KUShiftIdx];
       
   761 				*pixIdxPtr++ = vertStep>>iHorzSampleRatioSh[KVShiftIdx];
       
   762 				}
       
   763 			}
       
   764 		}
       
   765 	ASSERT(pixIdxPtr-iUVIndeces <= sizeof(iUVIndeces)/sizeof(iUVIndeces[0]) );
       
   766 	}
       
   767 
       
   768 void CJpgReadCodec::InitFrameL(CImageFrame& aDest)
       
   769 	{
       
   770 	JPEG_DEBUG1("CJpgReadCodec::InitFrameL(CImageFrame)");
       
   771 
       
   772 	PreInitFrameL();
       
   773 
       
   774 	// This JPEG codec does not support scaling when using destination of type CImageFrame
       
   775 	// It leaves if scaling has been requested.
       
   776 	//TInt reductionFactor = 0;
       
   777 	
       
   778 	if (iOperation != EDecodeNormal)
       
   779 		{
       
   780 		JPEG_LEAVE(KErrNotSupported, "No operations on CImageFrame");
       
   781 		}
       
   782 	
       
   783 	if (iExtensionManager->ScalerExtensionRequested())
       
   784 		{
       
   785 		JPEG_LEAVE(KErrNotSupported, "No scaling on CImageFrame");
       
   786 		}
       
   787 
       
   788 	if (iUseClipRect)
       
   789 		{
       
   790 		JPEG_LEAVE(KErrNotSupported, "No clipping on CImageFrame");
       
   791 		}
       
   792 	
       
   793 	// Check for implicit scaling.
       
   794 	TInt reductionFactor = 0;
       
   795 	if (!iUseClipRect)
       
   796 		{
       
   797 		reductionFactor = ReductionFactor(iFrameInfo.iSizeInPixels, aDest.FrameSizeInPixels());
       
   798 		}
       
   799 	
       
   800 	if (reductionFactor != 0)
       
   801 		{
       
   802 		JPEG_DEBUG2(" - reductionFactor = %d", reductionFactor);
       
   803 		JPEG_LEAVE(KErrNotSupported, "Bad reductionFactor");
       
   804 		}
       
   805 
       
   806 	InitComponentsL();
       
   807 
       
   808 	iCompConf[KYComp].iDequantFunc = &TQTable::DeQuantize;
       
   809 	iCompConf[KUComp].iDequantFunc = &TQTable::DeQuantize;
       
   810 	iCompConf[KVComp].iDequantFunc = &TQTable::DeQuantize;
       
   811 
       
   812 	iCompConf[KYComp].iDCT = &iFullDCT;
       
   813 	iCompConf[KUComp].iDCT = &iFullDCT;
       
   814 	iCompConf[KVComp].iDCT = &iFullDCT;
       
   815 
       
   816 	iCompConf[KYComp].iDCT->SetPrecision(iFrameInfo.iSamplePrecision);
       
   817 	iCompConf[KUComp].iDCT->SetPrecision(iFrameInfo.iSamplePrecision);
       
   818 	iCompConf[KVComp].iDCT->SetPrecision(iFrameInfo.iSamplePrecision);
       
   819 
       
   820 	// Create JPEG read codec extension and the appropriate image processor
       
   821 	ASSERT(iImageFrameCodecPtr == NULL);
       
   822 	delete iImageFrameCodecPtr;
       
   823 	iImageFrameCodecPtr = NULL;
       
   824 	iImageFrameCodecPtr = CJpgImageFrameReadCodec::NewL(&aDest);
       
   825 	iImageFrameCodecPtr->CreateImageProcessorL(iFrameInfo);
       
   826 
       
   827 	PostInitFrameL();
       
   828 	}
       
   829 
       
   830 //initialization for streaming
       
   831 void CJpgReadCodec::InitFrameL(TUid aFormat, TDecodeStreamCaps::TNavigation aNavigation)
       
   832 	{
       
   833 	JPEG_DEBUG1("InitFrameL(TUid)");
       
   834 
       
   835 	//validate format with frameinfo
       
   836 	PreInitFrameL();
       
   837 
       
   838 	ValidateFormatL(iFrameInfo, aFormat);
       
   839 
       
   840 	iIsBlockStreaming = ETrue;
       
   841 
       
   842 	iStreamFormat = aFormat;
       
   843 	iNavigation = aNavigation;
       
   844 
       
   845 	InitComponentsL();
       
   846 
       
   847 	iCompConf[KYComp].iDequantFunc = &TQTable::DeQuantize;
       
   848 	iCompConf[KUComp].iDequantFunc = &TQTable::DeQuantize;
       
   849 	iCompConf[KVComp].iDequantFunc = &TQTable::DeQuantize;
       
   850 
       
   851 	iCompConf[KYComp].iDCT = &iFullDCT;
       
   852 	iCompConf[KUComp].iDCT = &iFullDCT;
       
   853 	iCompConf[KVComp].iDCT = &iFullDCT;
       
   854 
       
   855 	iCompConf[KYComp].iDCT->SetPrecision(iFrameInfo.iSamplePrecision);
       
   856 	iCompConf[KUComp].iDCT->SetPrecision(iFrameInfo.iSamplePrecision);
       
   857 	iCompConf[KVComp].iDCT->SetPrecision(iFrameInfo.iSamplePrecision);
       
   858 
       
   859 	// Create JPEG read codec extension and the appropriate image processor
       
   860 	delete iImageFrameCodecPtr;
       
   861 	iImageFrameCodecPtr = NULL;
       
   862 	iImageFrameCodecPtr = CJpgImageFrameReadCodec::NewL(NULL);
       
   863 
       
   864 	PostInitFrameL();
       
   865 	}
       
   866 
       
   867 #if defined(__ARMCC__)
       
   868 #pragma pop
       
   869 #endif
       
   870 
       
   871 //get blocks for streaming
       
   872 void CJpgReadCodec::GetBlocksL(CImageFrame* aFrame, TInt aSeqPosition, TInt aNumBlocksToGet, TInt* aNumBlocksRead)
       
   873 	{
       
   874 	ASSERT(aNumBlocksRead);
       
   875 
       
   876 	if(aFrame == NULL || !(iNavigation == TDecodeStreamCaps::ENavigationRandomForward || iNavigation == TDecodeStreamCaps::ENavigationRandomBackwards))
       
   877 		{
       
   878 		JPEG_LEAVE(KErrArgument, "GetBlocks - bad params");
       
   879 		}
       
   880 
       
   881 	ValidateImageFrameBlockL(aFrame);
       
   882 
       
   883 	iImageFrameCodecPtr->SetImageFrameBlocksL(aFrame, iFrameInfo);
       
   884 
       
   885 	*aNumBlocksRead = 0;
       
   886 	iStreamDecodeConfig.iSeqPosition = aSeqPosition;
       
   887 	iStreamDecodeConfig.iNumBlocksToGet = aNumBlocksToGet;
       
   888 	iStreamDecodeConfig.iNumBlocksRead = aNumBlocksRead;
       
   889 	}
       
   890 
       
   891 //get blocks for streaming
       
   892 void CSequentialJpgReadCodec::GetBlocksL(CImageFrame* aFrame, TInt aSeqPosition, TInt aNumBlocksToGet, TInt* aNumBlocksRead)
       
   893 	{
       
   894 	if (aSeqPosition < 0)
       
   895 		{
       
   896 		JPEG_LEAVE(KErrArgument, "GetBlocksL - bad aSeqPosition");
       
   897 		}
       
   898 
       
   899 	iNeededMCU = aSeqPosition;
       
   900 
       
   901 	CJpgReadCodec::GetBlocksL(aFrame, aSeqPosition, aNumBlocksToGet, aNumBlocksRead);
       
   902 	}
       
   903 
       
   904 //get blocks for streaming
       
   905 void CJpgReadCodec::GetNextBlocksL(CImageFrame* aFrame, TInt aNumBlocksToGet, TInt* aNumBlocksRead, TBool* aHaveMoreBlocks)
       
   906 	{
       
   907 	ASSERT(aNumBlocksRead);
       
   908 	ASSERT(aHaveMoreBlocks);
       
   909 
       
   910 	if (aFrame == NULL || iNavigation != TDecodeStreamCaps::ENavigationSequentialForward)
       
   911 		{
       
   912 		JPEG_LEAVE(KErrArgument, "GetNextBlocksL - bad params");
       
   913 		}
       
   914 
       
   915 	ValidateImageFrameBlockL(aFrame);
       
   916 
       
   917 	iImageFrameCodecPtr->SetImageFrameBlocksL(aFrame, iFrameInfo);
       
   918 
       
   919 	*aNumBlocksRead = 0;
       
   920 	*aHaveMoreBlocks = ETrue;
       
   921 	iStreamDecodeConfig.iNumBlocksToGet = aNumBlocksToGet;
       
   922 	iStreamDecodeConfig.iNumBlocksRead = aNumBlocksRead;
       
   923 	iStreamDecodeConfig.iHaveMoreBlocks = aHaveMoreBlocks;
       
   924 	}
       
   925 
       
   926 //validates the blocks passed.
       
   927 void CJpgReadCodec::ValidateImageFrameBlockL(CImageFrame* aFrame)
       
   928 	{
       
   929 	ASSERT(aFrame);
       
   930 
       
   931 	TSize aBlockSizeInPixels = aFrame->FrameSizeInPixels();
       
   932 	TSize aRefSizeInPixels = TSize(iFrameInfo.MCUWidthInPixels(), iFrameInfo.MCUHeightInPixels());
       
   933 
       
   934 	const TFrameFormat& format = static_cast<const TFrameFormat&>(aFrame->FrameFormat());
       
   935 	TUid imageFrameFormatCode = format.FormatCode();
       
   936 
       
   937 	TInt oddPixelsWidth = aBlockSizeInPixels.iWidth % aRefSizeInPixels.iWidth;
       
   938 	TInt oddPixelsHeight = aBlockSizeInPixels.iHeight % aRefSizeInPixels.iHeight;
       
   939 
       
   940 	if (oddPixelsWidth != 0 || oddPixelsHeight != 0 || aBlockSizeInPixels.iHeight != aRefSizeInPixels.iHeight)
       
   941 		{
       
   942 		User::Leave(KErrNotSupported);
       
   943 		}
       
   944 
       
   945 	if(iIsBlockStreaming == EFalse)
       
   946 		{
       
   947 		User::Leave(KErrNotReady);
       
   948 		}
       
   949 
       
   950 	if(imageFrameFormatCode != KNullUid)
       
   951 		{
       
   952 		if(imageFrameFormatCode != iStreamFormat)
       
   953 			{
       
   954 			User::Leave(KErrArgument);
       
   955 			}
       
   956 		}
       
   957 	}
       
   958 
       
   959 //get buffer and blockSizeInPix for streaming
       
   960 TInt CJpgReadCodec::GetStreamBufferSizeL(TUid aFormatCode, TSize& aBlockSizeInPixels, TInt aNumBlocks)
       
   961 	{
       
   962 	return CJpgImageFrameProcessorUtility::RecommendedStreamBufferSizeL(iFrameInfo, aFormatCode, aBlockSizeInPixels, aNumBlocks);
       
   963 	}
       
   964 
       
   965 //validate format
       
   966 void CJpgReadCodec::ValidateFormatL(const TJpgFrameInfo& aFrameInfo, TUid aFormatCode)
       
   967 	{
       
   968 	TInt dataUnitCount=0;
       
   969 
       
   970 	if (aFrameInfo.iNumberOfComponents == 1)
       
   971 		{
       
   972 		dataUnitCount = 1;
       
   973 		}
       
   974 	else
       
   975 		{
       
   976 		dataUnitCount = 0;
       
   977 		for (TInt index = 0; index < aFrameInfo.iNumberOfComponents; index++)
       
   978 			{
       
   979 			dataUnitCount += aFrameInfo.iComponent[index].iHorzSampleFactor *
       
   980 							 aFrameInfo.iComponent[index].iVertSampleFactor;
       
   981 			}
       
   982 		}
       
   983 
       
   984 	switch (dataUnitCount)
       
   985 		{
       
   986 
       
   987 		case 1: // Monochrome
       
   988 			{
       
   989 			if (aFormatCode != KUidFormatYUVMonochrome)
       
   990 				{
       
   991 				// error transcoding not supported
       
   992 				User::Leave(KErrNotSupported);
       
   993 				}
       
   994 			break;
       
   995 			}
       
   996 
       
   997 		case 4: // 4:2:2
       
   998 			{
       
   999 			if (aFormatCode != KUidFormatYUV422Interleaved)
       
  1000 				{
       
  1001 				// error transcoding not supported
       
  1002 				User::Leave(KErrNotSupported);
       
  1003 				}
       
  1004 			break;
       
  1005 			}
       
  1006 
       
  1007 		case 6: // 4:2:0
       
  1008 			{
       
  1009 			if (!(aFormatCode == KUidFormatYUV420Planar || aFormatCode == KUidFormatYUV420PlanarReversed))
       
  1010 				{
       
  1011 				// error transcoding not supported
       
  1012 				User::Leave(KErrNotSupported);
       
  1013 				}
       
  1014 			break;
       
  1015 			}
       
  1016 
       
  1017 		default:
       
  1018 			{
       
  1019 			User::Leave(KErrNotSupported);
       
  1020 			break;
       
  1021 			}
       
  1022 		}
       
  1023 	}
       
  1024 
       
  1025 //
       
  1026 // This function should be called at beginning of the
       
  1027 // various InitFrameL versions. It performs initialisation
       
  1028 // that's common to all forms of image.
       
  1029 //
       
  1030 void CJpgReadCodec::PreInitFrameL()
       
  1031 	{
       
  1032 	JPEG_DEBUG1("PreInitFrameL()");
       
  1033 	JPEG_DEBUG2(" - MCU pixel width: %d", iFrameInfo.MCUWidthInPixels());
       
  1034 	JPEG_DEBUG2(" - MCU pixel height: %d", iFrameInfo.MCUHeightInPixels());
       
  1035 
       
  1036 	iHorzMCUBlkCount = 0;
       
  1037 	iScalingFactor = 1;
       
  1038 	iMCUsPerBuffer = (iFrameInfo.iProgressive ? 1 : iFrameInfo.iMCUBlocksPerLine);
       
  1039 	ASSERT(iMCUsPerBuffer > 0);
       
  1040 	
       
  1041 	iMonochrome = (iFrameInfo.iNumberOfComponents == 1);
       
  1042 	
       
  1043 	TInt interval = iFrameInfo.iRestartInterval;
       
  1044 	iRestartMCUCount = (interval > 0 ? interval : KErrNotFound);
       
  1045 	JPEG_DEBUG2(" - iRestartMCUCount = %d", iRestartMCUCount);
       
  1046 	
       
  1047 	iMaxHorzSampleFactor = iFrameInfo.iMaxHorzSampleFactor;
       
  1048 	iMaxVertSampleFactor = iFrameInfo.iMaxVertSampleFactor;
       
  1049 	JPEG_DEBUG2(" - iMaxHorzSampleFactor = %d", iMaxHorzSampleFactor);
       
  1050 	JPEG_DEBUG2(" - iMaxVertSampleFactor = %d", iMaxVertSampleFactor);
       
  1051 	
       
  1052 	// Get info from the extension manager. The InitFrameL function can
       
  1053 	// decide whether or not the operation is supported.
       
  1054 	ASSERT(iExtensionManager);
       
  1055 
       
  1056 	if (iAutoRotateFlag > 1 && iAutoRotateFlag < 9) 
       
  1057 		{
       
  1058 		// To ensure operation extension is created
       
  1059 		iExtensionManager->CreateExtensionForAutoRotateL();
       
  1060 		iOperation = iExtensionManager->OperationL(iAutoRotateFlag);
       
  1061 		}
       
  1062 	else 
       
  1063 		{
       
  1064 		iOperation = iExtensionManager->Operation();
       
  1065 		}
       
  1066 	
       
  1067 	// check out if we need to clip.
       
  1068 	iUseClipRect = EFalse;
       
  1069 	if (iExtensionManager->ClippingRectExtensionRequested())
       
  1070 		{
       
  1071 		iUseClipRect = ETrue;
       
  1072 		}
       
  1073 	
       
  1074 	ResetState();
       
  1075 	}
       
  1076 
       
  1077 //
       
  1078 //
       
  1079 //
       
  1080 void CJpgReadCodec::PostInitFrameL()
       
  1081 	{
       
  1082 	// Default implementation does nothing.
       
  1083 	}
       
  1084 
       
  1085 //
       
  1086 //
       
  1087 //
       
  1088 void CJpgReadCodec::StoreState()
       
  1089 	{
       
  1090 	iInitialDataPtr = iDataPtr;
       
  1091 	iInitialDataValue = iDataValue;
       
  1092 	iInitialBitsLeft = iBitsLeft;
       
  1093 	iBitBufferPtrLimit = NULL;
       
  1094 
       
  1095 	for (TInt i = 0; i < KJpgNumberOfComponents; i++)
       
  1096 		{
       
  1097 		iInitialDCPredictor[i] = iDCPredictor[i];
       
  1098 		}
       
  1099 	}
       
  1100 
       
  1101 //
       
  1102 //
       
  1103 //
       
  1104 void CJpgReadCodec::RestoreState()
       
  1105 	{
       
  1106 	iDataPtr = iInitialDataPtr;
       
  1107 	iBitBufferPtrLimit = NULL;
       
  1108 	iDataValue = iInitialDataValue;
       
  1109 	iBitsLeft = iInitialBitsLeft;
       
  1110 
       
  1111 	for (TInt i = 0; i < KJpgNumberOfComponents; i++)
       
  1112 		{
       
  1113 		iDCPredictor[i] = iInitialDCPredictor[i];
       
  1114 		}
       
  1115 	}
       
  1116 
       
  1117 //
       
  1118 //
       
  1119 //
       
  1120 void CJpgReadCodec::ResetState()
       
  1121 	{
       
  1122 	for (TInt i = 0; i < KJpgNumberOfComponents; i++)
       
  1123 		{
       
  1124 		iDCPredictor[i] = 0;
       
  1125 		}
       
  1126 
       
  1127 	iBitsLeft = 0;
       
  1128 	iBitBufferPtrLimit = NULL;
       
  1129 	}
       
  1130 
       
  1131 //
       
  1132 // Returns the number of bytes that had to be skipped before the restart marker was found.
       
  1133 //
       
  1134 TInt CJpgReadCodec::RestartStateL()
       
  1135 	{
       
  1136 	const TUint8* startPtr = iDataPtr;
       
  1137 	const TUint8* readLimit = iDataPtrLimit - 2;
       
  1138 
       
  1139 	// skip the data until the marker is found
       
  1140 	while (*iDataPtr != 0xff && iDataPtr < readLimit)
       
  1141 		{
       
  1142 		iDataPtr++;
       
  1143 		}
       
  1144 
       
  1145 	if (*iDataPtr != 0xff)
       
  1146 		{
       
  1147 		User::Leave(KErrCompletion);
       
  1148 		}
       
  1149 
       
  1150 	iDataPtr++;
       
  1151 
       
  1152 	TInt marker = *iDataPtr++;
       
  1153 
       
  1154 	if (marker == (KJpgEOISignature & 0x00ff))
       
  1155 		{
       
  1156 		User::Leave(KErrEof);
       
  1157 		}
       
  1158 	else if ((marker & 0xf0) != 0xd0)
       
  1159 		{
       
  1160 #if !defined(RELAX_JPEG_STRICTNESS)
       
  1161 		User::Leave(KErrCorrupt);
       
  1162 #endif
       
  1163 		}
       
  1164 
       
  1165 	// if iRestartInterval is 0, iRestartMCUCount is set to a negative value (KErrNotFound) to skip the 0 trigger points that would call RestartStateL
       
  1166 	// This is done to solve the problem that on some images the iRestartInterval marker is 0 on every frame
       
  1167 	iRestartMCUCount = iFrameInfo.iRestartInterval > 0 ? iFrameInfo.iRestartInterval : KErrNotFound;
       
  1168 	ResetState();
       
  1169 	StoreState();
       
  1170 	
       
  1171 	return iDataPtr - startPtr;
       
  1172 	}
       
  1173 
       
  1174 CJpgImageFrameReadCodec* CJpgReadCodec::ImageFrameCodec()
       
  1175 	{
       
  1176 	return iImageFrameCodecPtr;
       
  1177 	}
       
  1178 
       
  1179 TInt CJpgReadCodec::ReducedSize(const TSize& aOriginalSize, TInt aReductionFactor, TSize& aReducedSize) const
       
  1180 	{
       
  1181 	aReducedSize = aOriginalSize;
       
  1182 	if (aReductionFactor < 0 || aReductionFactor > 3)
       
  1183 		{
       
  1184 		return KErrArgument;
       
  1185 		}
       
  1186 	else
       
  1187 		{
       
  1188 		return CImageReadCodec::ReducedSize(aOriginalSize, aReductionFactor, aReducedSize);	
       
  1189 		}
       
  1190 	}
       
  1191 
       
  1192 #if defined(__ARMCC__)
       
  1193 // use ARM instruction for performance-critical code
       
  1194 #pragma push
       
  1195 #pragma arm 
       
  1196 #pragma O3 
       
  1197 #pragma Otime
       
  1198 #endif
       
  1199 
       
  1200 TInt CJpgReadCodec::FillBitBufferL(TInt aBLeft)
       
  1201 	{
       
  1202 	const TInt KBytesToFetch= 4;
       
  1203 	const TUint8* dataPtr   = iDataPtr;
       
  1204 	
       
  1205 	const TUint8* bitBufLim = iBitBufferPtrLimit;
       
  1206 	if (dataPtr + KBytesToFetch >=  bitBufLim)
       
  1207 		{
       
  1208 		bitBufLim = JpegFillBuffer(dataPtr);
       
  1209 		}
       
  1210 		
       
  1211 	register TUint dataValue = iDataValue;
       
  1212 	
       
  1213 	if (dataPtr + KBytesToFetch < bitBufLim )
       
  1214 		{
       
  1215 		if (aBLeft == 0)
       
  1216 		    {
       
  1217 		    aBLeft = 8;
       
  1218 		    dataValue = (*dataPtr++);
       
  1219 		    }
       
  1220 		dataValue = (dataValue<<8) | (*dataPtr++);
       
  1221 		dataValue = (dataValue<<8) | (*dataPtr++);
       
  1222 		dataValue = (dataValue<<8) | (*dataPtr++);
       
  1223 
       
  1224 		iBitsLeft = aBLeft + (KBytesToFetch-1) * 8;    
       
  1225 
       
  1226 		iDataValue= dataValue;
       
  1227 		iDataPtr  = dataPtr;
       
  1228 
       
  1229 		return iBitsLeft;
       
  1230 		}
       
  1231 		
       
  1232 	if (dataPtr == iDataPtrLimit) // no more data available
       
  1233 		{
       
  1234 		if (aBLeft) // there are some bits left so make use of them
       
  1235 			{
       
  1236 			return (iBitsLeft = aBLeft);
       
  1237 			}
       
  1238 		// no more data in buffer - signal that
       
  1239 		User::Leave(KErrCompletion); 
       
  1240 		}
       
  1241 		
       
  1242 	iDataValue = (dataValue<<8) | (*iDataPtr++);
       
  1243 	iBitsLeft  = aBLeft + 8;
       
  1244 
       
  1245 	if ((iDataValue & 0xFF) == 0xFF)
       
  1246 		{
       
  1247 		if (iDataPtr == iDataPtrLimit)
       
  1248 			{
       
  1249 			// ----+ +-------
       
  1250 			//  |FF| |??|??|
       
  1251 			// ----+ +-------
       
  1252 			--iDataPtr;
       
  1253 			User::Leave(KErrCompletion);
       
  1254 			}
       
  1255 
       
  1256 		// When the byte sequence 0xFF occurs in encoded image data it must be followed
       
  1257 		// by 0x00 or the decoder will consider it a marker. The 0x00 is ignored
       
  1258 		// by the decoder.
       
  1259 		
       
  1260 		// --------...
       
  1261 		//  |FF|??|
       
  1262 		// --------...
       
  1263 		TInt marker = *iDataPtr++;
       
  1264 		if (marker)//Since (FF,00) stream is valid we send it.For a Non-Zero marker we need to do something
       
  1265 			{
       
  1266 			// It's a proper marker
       
  1267 			if (iBitsLeft > 8) // there are stiil some bits to decode
       
  1268 				{
       
  1269 			// Before: iDataValue = [xxxxxxxx][xxxxxxxx][xxxxxxxx][ffffffff]
       
  1270 				iBitsLeft-=8;
       
  1271 				iDataValue >>=8;
       
  1272 				iDataPtr-=2;
       
  1273 			// After: iDataValue = [00000000][xxxxxxxx][xxxxxxxxx][xxxxxxxx]
       
  1274 				return iBitsLeft;
       
  1275 				}
       
  1276 			// End of encoded image data stream?
       
  1277 			if (marker == (KJpgEOISignature&0xFF)) //Allow 0xFF as a valid marker only report KErrEof in case of EOI marker
       
  1278 				{
       
  1279 				User::Leave(KErrEof);	// we've reached the end of the file
       
  1280 				}
       
  1281 			else
       
  1282 				{
       
  1283 				//If marker is a special marker like 0xFF we need to give a valid iDataValue..
       
  1284 				if(marker == KJpgMarkerByte)
       
  1285 					{
       
  1286 					while(iDataPtr<iDataPtrLimit && *iDataPtr == KJpgMarkerByte)
       
  1287 						{
       
  1288 						iDataPtr++;
       
  1289 						}
       
  1290 					
       
  1291 					if (iDataPtr==iDataPtrLimit)
       
  1292 						{
       
  1293 						--iDataPtr;
       
  1294 						User::Leave(KErrCompletion);
       
  1295 						}
       
  1296 					else
       
  1297 						{
       
  1298 						//Check for 0x00 marker since (0xFF,0x00) is a valid stream
       
  1299 						if(*iDataPtr==0x00)	
       
  1300 							{
       
  1301 							iDataPtr+=1;
       
  1302 							return iBitsLeft;
       
  1303 							}
       
  1304 						}
       
  1305 					}
       
  1306 				iDataPtr-=1; // we'd accept some malformed files, otherwise User::Leave(KErr)
       
  1307 				}
       
  1308 			}
       
  1309 		}
       
  1310 	return iBitsLeft;
       
  1311 	}
       
  1312 
       
  1313 //
       
  1314 // Examine the buffer given by ProcessL for 0xFF sequences.
       
  1315 // This allows for less checking in the FillBitBufferL function.
       
  1316 //
       
  1317 inline const TUint8* CJpgReadCodec::JpegFillBuffer(const TUint8* aDataPtr)
       
  1318 	{
       
  1319 	register const TUint8* limit = Min(iDataPtrLimit - 1, aDataPtr + KMarkerLookAhead + 1);
       
  1320 
       
  1321 	// Try to ignore markers that are at the start of the buffer, except for EOI.
       
  1322 	while ((aDataPtr < limit) && (*aDataPtr != 0xFF))
       
  1323 		{
       
  1324 		++aDataPtr;
       
  1325 		}
       
  1326 
       
  1327 	return (iBitBufferPtrLimit = (aDataPtr - 1));
       
  1328 	}
       
  1329 
       
  1330 FORCEDINLINE TBool CJpgReadCodec::NextBitL()
       
  1331 	{
       
  1332 	if (iBitsLeft == 0)
       
  1333 		{
       
  1334 		FillBitBufferL(0);
       
  1335 		}
       
  1336 	return (iDataValue & (1 << --iBitsLeft));
       
  1337 	}
       
  1338 
       
  1339 void CJpgReadCodec::SetAutoRotateFlag(TUint16 aAutoRotateFlag)
       
  1340 	{
       
  1341 	iAutoRotateFlag = aAutoRotateFlag;
       
  1342 	}
       
  1343 
       
  1344 void CJpgReadCodec::GetComponentBlockL(TDataUnit& aDestination,TInt& aNumValues,TInt& aDCPrediction,const TDecHuffmanTable& aDCTable,const TDecHuffmanTable& aACTable)
       
  1345 	{
       
  1346 	TInt size = GetHuffmanCodeL(aDCTable);
       
  1347 	TInt amplitude = (size > 0) ? GetBinaryNumberL( size & 0x1F ) : 0;
       
  1348 	aDCPrediction += amplitude;
       
  1349 
       
  1350 	if (aDCPrediction > KMaxTInt16 || aDCPrediction < KMinTInt16)
       
  1351 		{
       
  1352 		JPEG_LEAVE(KErrCorrupt, "Bad component block");
       
  1353 		}
       
  1354 	
       
  1355 	if (iScalingFactor != -4) 
       
  1356 	    {
       
  1357 		FillCompZ(aDestination, KJpgDCTBlockSize);
       
  1358 		TInt16* valuePtr = aDestination.iCoeff;
       
  1359 		TInt16* valuePtrLimit = valuePtr + KJpgDCTBlockSize;
       
  1360 
       
  1361 		*valuePtr++ = TInt16(aDCPrediction);
       
  1362 
       
  1363 		while (valuePtr < valuePtrLimit)
       
  1364 			{
       
  1365 			TInt s = GetHuffmanCodeL(aACTable);
       
  1366 			if (s == 0) // End of block
       
  1367 				{
       
  1368 				break;
       
  1369 				}
       
  1370 			else
       
  1371 				{
       
  1372 				TInt r = s >> 4;
       
  1373 				s &= 0x0f;
       
  1374 				if (s > 0)
       
  1375 					{
       
  1376 					valuePtr += r;
       
  1377 
       
  1378 					if (valuePtr < valuePtrLimit)
       
  1379 						{
       
  1380     				    *valuePtr++ = GetBinaryNumberL(s);
       
  1381 						}
       
  1382 					}
       
  1383 				else if (r == 15) // Zero run length
       
  1384 					{
       
  1385 					valuePtr += 16;
       
  1386 					}
       
  1387 				}
       
  1388 			}
       
  1389 
       
  1390 		if (valuePtr > valuePtrLimit)
       
  1391     	    {
       
  1392 			valuePtr = valuePtrLimit;
       
  1393     	    }
       
  1394 
       
  1395 		aNumValues = valuePtr - aDestination.iCoeff;
       
  1396 	    }
       
  1397 	else    // for 1/8 scaling we need only DC value, so perform fast block skipping
       
  1398 	    {
       
  1399 	    aNumValues      = 1;
       
  1400     	
       
  1401     	aDestination.iCoeff[0] = TInt16(aDCPrediction);
       
  1402     	TInt numValuesRead = 1; //we've already got DC value
       
  1403     	do 
       
  1404     		{
       
  1405     		TInt s = GetHuffmanCodeL(aACTable);
       
  1406     		if (s == 0) // End of block
       
  1407     		    {
       
  1408     		    break;
       
  1409     		    }
       
  1410     		else
       
  1411     			{
       
  1412     			TInt r = s >> 4;
       
  1413     			s &= 0x0f;
       
  1414     			if (s > 0)
       
  1415     				{
       
  1416     				numValuesRead += r;
       
  1417 
       
  1418     				if (numValuesRead < KJpgDCTBlockSize)
       
  1419     				    {
       
  1420     				    numValuesRead++;
       
  1421     				    SkipBitsQuickL(s);
       
  1422     				    }
       
  1423     				}
       
  1424     			else if (r == 15) // Zero run length
       
  1425     				{
       
  1426     				numValuesRead += 16;
       
  1427     				}
       
  1428     			}
       
  1429     		} while (numValuesRead < KJpgDCTBlockSize);
       
  1430 	    }
       
  1431 	}
       
  1432 
       
  1433 TInt CJpgReadCodec::GetHuffmanCodeL(const TDecHuffmanTable& aTable)
       
  1434 	{
       
  1435 	TInt bLeft = iBitsLeft;
       
  1436 	if (bLeft < KJpgHuffmanLookAhead)
       
  1437 		{
       
  1438 		bLeft = FillBitBufferL(bLeft);
       
  1439 		}
       
  1440 
       
  1441 	TUint dv = iDataValue;
       
  1442 
       
  1443 	TInt nb=1;
       
  1444 	//
       
  1445 	if (bLeft >= KJpgHuffmanLookAhead)
       
  1446 		{
       
  1447 		
       
  1448 		TUint32 fastLook = (dv >> (bLeft - KJpgHuffmanLookAhead)) & KJpgHuffmanLookAheadMask;
       
  1449 		register TUint32 lookupEntry = aTable.GetLookupEntry(fastLook);
       
  1450 		if (aTable.Found(lookupEntry))
       
  1451 			{
       
  1452 			iBitsLeft = (bLeft - aTable.GetSize(lookupEntry));
       
  1453 			return aTable.GetCode(lookupEntry);
       
  1454 			}
       
  1455 		else
       
  1456 			{
       
  1457 			nb = (KJpgHuffmanLookAhead+1 > bLeft)? bLeft : KJpgHuffmanLookAhead+1;
       
  1458 			}
       
  1459 		}
       
  1460 
       
  1461 	register TUint index   = 0;
       
  1462 	TInt bitCount = 0;
       
  1463 
       
  1464 	ASSERT(nb>0);
       
  1465 	register TUint32 look = dv << (32 - bLeft);
       
  1466 	iBitsLeft -= nb;
       
  1467 	do
       
  1468 		{
       
  1469 		index = (index << 1) + 1;
       
  1470 		index +=((look & TUint(1<<31)) != 0);
       
  1471 		look<<=1;
       
  1472 		} while (++bitCount < nb);
       
  1473 
       
  1474 	const TUint8* codeIdxHash = aTable.GetCodeIdxHash();
       
  1475 	
       
  1476 	for (; bitCount <= 16; bitCount++)
       
  1477 		{
       
  1478       	TInt first    = codeIdxHash[bitCount];
       
  1479       	TInt last    = codeIdxHash[bitCount+1];
       
  1480 		while (last >= first)
       
  1481          	{
       
  1482          	register TInt notFoundPosition = (first + last) >> 1;
       
  1483          	TInt codeIndex = aTable.GetIndex(notFoundPosition);
       
  1484 
       
  1485 			if (index < codeIndex)
       
  1486 				{
       
  1487 				last = notFoundPosition - 1;
       
  1488 				}
       
  1489 			else if (index > codeIndex)
       
  1490 				{
       
  1491 				first = notFoundPosition + 1;
       
  1492 				}
       
  1493 			else
       
  1494 				{
       
  1495             	return aTable.GetIndexedCode(notFoundPosition);
       
  1496             	}
       
  1497          	}
       
  1498 
       
  1499 		index = (index << 1) + 1;
       
  1500 		index += (NextBitL()!=0);
       
  1501 		}
       
  1502 
       
  1503 #if !defined(RELAX_JPEG_STRICTNESS)
       
  1504 	User::Leave(KErrCorrupt);
       
  1505 #endif
       
  1506 
       
  1507 	return aTable.GetIndexedCode(0);
       
  1508 	}
       
  1509 
       
  1510 FORCEDINLINE void CJpgReadCodec::SkipBitsQuickL(TInt aNumOfBits)
       
  1511     {
       
  1512     TInt bLeft = iBitsLeft;
       
  1513         
       
  1514     FOREVER
       
  1515         {
       
  1516         bLeft   -=  aNumOfBits;
       
  1517         if (bLeft >= 0)
       
  1518             {
       
  1519             iBitsLeft = bLeft;
       
  1520             return;
       
  1521             }
       
  1522         aNumOfBits = -bLeft;
       
  1523         iBitsLeft = 0;
       
  1524         bLeft = FillBitBufferL(0);
       
  1525         }
       
  1526     }
       
  1527 
       
  1528 FORCEDINLINE TInt CJpgReadCodec::GetBinaryNumberQuickL(TInt aLength)
       
  1529 	{
       
  1530 	register TInt bLeft  = iBitsLeft;
       
  1531 	register TUint number = 0;
       
  1532 	register TBitBuffer bitBuf;
       
  1533 
       
  1534 	FOREVER
       
  1535 		{
       
  1536 		bitBuf = iDataValue;
       
  1537 		
       
  1538 		bLeft -= aLength;
       
  1539 		if (bLeft >= 0)
       
  1540 		    {
       
  1541 		    break;
       
  1542 		    }
       
  1543 		bLeft  += aLength;
       
  1544 		aLength -= bLeft;
       
  1545 	    number |= ((bitBuf & ((1<<bLeft)-1)) << aLength);
       
  1546     
       
  1547 	    bLeft = FillBitBufferL(0);
       
  1548 		}
       
  1549 		
       
  1550 	iBitsLeft = bLeft;
       
  1551 	
       
  1552 	number |= ((bitBuf>>bLeft) & ((1<<aLength)-1));
       
  1553 	return number;	
       
  1554 	}
       
  1555 
       
  1556 FORCEDINLINE TInt16 CJpgReadCodec::GetPositiveBinaryNumberL(TInt aLength)
       
  1557 	{
       
  1558     return TInt16( GetBinaryNumberQuickL(aLength) );
       
  1559 	}
       
  1560 
       
  1561 FORCEDINLINE TInt16 CJpgReadCodec::GetBinaryNumberL(TInt aLength)
       
  1562     {
       
  1563 	TInt mask  = (-1) << (aLength - 1);
       
  1564 	TInt number = GetBinaryNumberQuickL(aLength);
       
  1565 	return TInt16( (number & mask)? number : number + ( mask<<1 ) + 1);
       
  1566     }
       
  1567 
       
  1568 /**
       
  1569  	This class is to provide with "write pixel" functionality
       
  1570  	for writting pixels into TRgb-type buffer
       
  1571 */
       
  1572 class TRgbWriter
       
  1573 	{
       
  1574 public:
       
  1575 	inline
       
  1576 	static void WritePixel(TRgb* aPtr, TInt aY, TInt aU, TInt aV)
       
  1577 		{
       
  1578 		*aPtr = TYCbCr::YCbCrtoRGB(aY, aU, aV);
       
  1579 		}
       
  1580 	inline
       
  1581 	static TRgb* ShiftPtr(TRgb* aPtr, TInt aUnitsOffs)
       
  1582 		{
       
  1583 		return  aPtr + aUnitsOffs;
       
  1584 		}
       
  1585 	};
       
  1586 
       
  1587 /**
       
  1588  	This class is to provide with "write pixel" functionality
       
  1589  	for writting pixels into EColor16M-type buffer i.e. 3 bytes per pixel
       
  1590 */
       
  1591 class TRawWriter
       
  1592 	{
       
  1593 public:
       
  1594 	inline
       
  1595 	static void WritePixel(TRgb* aPtr, TInt aY, TInt aU, TInt aV)
       
  1596 		{
       
  1597 		TYCbCr::YCbCrtoRawRGB(aY, aU, aV, aPtr);
       
  1598 		}
       
  1599 	inline
       
  1600 	static TRgb* ShiftPtr(TRgb* aPtr, TInt aUnitsOffs)
       
  1601 		{
       
  1602 		return  reinterpret_cast<TRgb*>(reinterpret_cast<TUint8*>(aPtr) + (aUnitsOffs<<1) + aUnitsOffs);
       
  1603 		}
       
  1604 	};
       
  1605 
       
  1606 /**
       
  1607  	This class is to provide with "write pixel" functionality
       
  1608  	for writting pixels into EColor16M-type buffer i.e. 3 bytes per pixel
       
  1609  	It is similar to the TRawWriter but uses inline version of YUV->RGB
       
  1610  	conversion function
       
  1611 */
       
  1612 class TRawInlineWriter
       
  1613 	{
       
  1614 public:
       
  1615 	inline
       
  1616 	static void WritePixel(TRgb* aPtr, TInt aY, TInt aU, TInt aV)
       
  1617 		{
       
  1618 		TYCbCr::YCbCrtoRawRGBInl(aY, aU, aV, aPtr);
       
  1619 		}
       
  1620 	inline
       
  1621 	static TRgb* ShiftPtr(TRgb* aPtr, TInt aUnitsOffs)
       
  1622 		{
       
  1623 		return  reinterpret_cast<TRgb*>(reinterpret_cast<TUint8*>(aPtr) + (aUnitsOffs<<1) + aUnitsOffs);
       
  1624 		}
       
  1625 	};
       
  1626 
       
  1627 /**
       
  1628  	This class is to provide with "write pixel" functionality
       
  1629  	for writting pixels into EColor64K-type buffer i.e. 2 bytes per pixel
       
  1630 */
       
  1631 class TRaw64KColorWriter
       
  1632 	{
       
  1633 public:
       
  1634 	inline
       
  1635 	static void WritePixel(TRgb* aPtr, TInt aY, TInt aU, TInt aV)
       
  1636 		{
       
  1637 		TYCbCr::YCbCrtoRaw64K(aY, aU, aV, aPtr);
       
  1638 		}
       
  1639 	inline
       
  1640 	static TRgb* ShiftPtr(TRgb* aPtr, TInt aUnitsOffs)
       
  1641 		{
       
  1642 		return  reinterpret_cast<TRgb*>(reinterpret_cast<TUint8*>(aPtr) + (aUnitsOffs<<1) );
       
  1643 		}
       
  1644 	};
       
  1645 
       
  1646 inline void CJpgReadCodec::WriteMCU()
       
  1647 	{
       
  1648 	JPEG_ASSERT(iMcuWriteFunc);
       
  1649 	(this->*iMcuWriteFunc)();
       
  1650 	}
       
  1651 
       
  1652 //
       
  1653 // Calculate where in the intermediate buffer this MCU should be drawn.
       
  1654 //
       
  1655 TInt CJpgReadCodec::GetMCURenderOffset()
       
  1656 	{
       
  1657 	TInt mcuPos;
       
  1658 
       
  1659 	JPEG_ASSERT(iMCUHorizExtent > 0);
       
  1660 
       
  1661 	if (iFillBufferBackwards)
       
  1662 		{
       
  1663 		JPEG_ASSERT(!iProgressive);
       
  1664 		mcuPos = iMCUsPerBuffer - iHorzMCUBlkCount - 1;
       
  1665 		}
       
  1666 	else
       
  1667 		{
       
  1668 		// Fill from left to right.
       
  1669 		mcuPos = iHorzMCUBlkCount;
       
  1670 		}
       
  1671 
       
  1672 	JPEG_ASSERT(mcuPos >= 0);
       
  1673 
       
  1674 	// iMCUHorizExtent has already been scaled by CalculateRenderingParams().
       
  1675 	return (mcuPos * iMCUHorizExtent);
       
  1676 
       
  1677 	}
       
  1678 
       
  1679 //
       
  1680 // Writes a monochrome MCU.
       
  1681 //
       
  1682 void CJpgReadCodec::WriteMonoMCU()
       
  1683 	{
       
  1684 	const TInt16* yComp = iComponent[KYComp]->iCoeff;
       
  1685 
       
  1686 	if (iScalingFactor == -4)
       
  1687 		{
       
  1688 		TInt pixelsToSkip = GetMCURenderOffset() + iFirstPixelOffset;
       
  1689 		TRgb* writeAddress = iRgbBuffer + pixelsToSkip;
       
  1690 		/* Coverity may flag as overrun of array yComp by indexing, which is false positive. There is more than one TDataUnit object pointed to by 
       
  1691 		iComponent[KYComp], which Coverity may fail to take into account */
       
  1692 		for (TInt j = 0; j < iMaxVertSampleFactor; j++)
       
  1693 			{
       
  1694 			for (TInt i = 0; i < iMaxHorzSampleFactor; i++)
       
  1695 				{
       
  1696 				*writeAddress = TRgb::Gray256(ColorCcomponent::ClampColorComponent(yComp[0]));
       
  1697 				writeAddress += iPixelIncrement;
       
  1698 				yComp += KJpgDCTBlockSize;
       
  1699 				}
       
  1700 			writeAddress += iRgbBufNextLineOffs;
       
  1701 			}
       
  1702 		}
       
  1703 	else
       
  1704 		{
       
  1705 		const TInt KYBlockOffset	= KJpgDCTBlockWidth-(iMaxHorzSampleFactor * KJpgDCTBlockSize);
       
  1706 
       
  1707 		TInt pixelsToSkip = GetMCURenderOffset() + iFirstPixelOffset;
       
  1708 		TRgb* writeAddress = iRgbBuffer + pixelsToSkip;
       
  1709 
       
  1710 		for (TInt sf = iMaxVertSampleFactor * KJpgDCTBlockWidth; sf;)
       
  1711 			{
       
  1712 			TInt hsf = iMaxHorzSampleFactor;
       
  1713 			do
       
  1714 				{
       
  1715 				TInt i = KJpgDCTBlockWidth / 2;
       
  1716 				do
       
  1717 					{
       
  1718 					*writeAddress = TRgb::Gray256(ColorCcomponent::ClampColorComponent(*yComp++));
       
  1719 					writeAddress += iPixelIncrement;
       
  1720 					*writeAddress = TRgb::Gray256(ColorCcomponent::ClampColorComponent(*yComp++));
       
  1721 					writeAddress += iPixelIncrement;
       
  1722 					}
       
  1723 				while (--i);
       
  1724 
       
  1725 				yComp += (KJpgDCTBlockSize - KJpgDCTBlockWidth);
       
  1726 				}
       
  1727 			while (--hsf);
       
  1728 
       
  1729 			--sf;
       
  1730 			yComp 		+= (sf & (KJpgDCTBlockWidth-1))? KYBlockOffset: -(KJpgDCTBlockSize-KJpgDCTBlockWidth);
       
  1731 			writeAddress += iRgbBufNextLineOffs;
       
  1732 			}
       
  1733 		}
       
  1734 	}
       
  1735 
       
  1736 void CJpgReadCodec::WriteDiv8ScaledMCU16M()
       
  1737 	{
       
  1738 	WriteDiv8MCUImpl<TRawWriter>();
       
  1739 	}
       
  1740 
       
  1741 void CJpgReadCodec::WriteDiv8ScaledMCU()
       
  1742 	{
       
  1743 	WriteDiv8MCUImpl<TRgbWriter>();
       
  1744 	}
       
  1745 
       
  1746 void CJpgReadCodec::WriteDiv8ScaledMCU64K()
       
  1747 	{
       
  1748 	WriteDiv8MCUImpl<TRaw64KColorWriter>();
       
  1749 	}
       
  1750 
       
  1751 template <class T>
       
  1752 inline void CJpgReadCodec::WriteDiv8MCUImpl()
       
  1753 	{
       
  1754 	ASSERT(iScalingFactor == -4);
       
  1755 
       
  1756 	TInt16* yComp = iComponent[0]->iCoeff;
       
  1757 
       
  1758 	TUVidxElemType* uVIndeces = iUVIndeces;
       
  1759 
       
  1760 	TInt pixelsToSkip = GetMCURenderOffset() + iFirstPixelOffset;
       
  1761 	TRgb* writeAddress = T::ShiftPtr(iRgbBuffer, pixelsToSkip);
       
  1762 
       
  1763 	const TInt16* uComp = iComponent[KUComp]->iCoeff;
       
  1764 	const TInt16* vComp = iComponent[KVComp]->iCoeff;
       
  1765 
       
  1766 	TInt hsf = iMaxHorzSampleFactor;
       
  1767 	TInt vsf = iMaxVertSampleFactor;
       
  1768 	/* Coverity may flag as overrun of array on indexing yComp. This is false positive. Coverity doesn't take into account that 
       
  1769 	iComponent[0] can point to more than one TDataUnit.
       
  1770 	*/
       
  1771 	do
       
  1772 		{
       
  1773 		do
       
  1774 			{
       
  1775 			const TInt16 uValue = uComp[*uVIndeces];
       
  1776 			uVIndeces++;
       
  1777 			const TInt16 vValue = vComp[*uVIndeces];
       
  1778 			uVIndeces++;
       
  1779 			T::WritePixel(writeAddress, *yComp, uValue, vValue);
       
  1780 			writeAddress = T::ShiftPtr(writeAddress, iPixelIncrement);
       
  1781 
       
  1782 			yComp += KJpgDCTBlockSize;
       
  1783 			}
       
  1784 		while (--hsf);
       
  1785 
       
  1786 		hsf = iMaxHorzSampleFactor;
       
  1787 		uVIndeces += (hsf << 4); // 2 * hsf * KJpgBlockWidth
       
  1788 		writeAddress = T::ShiftPtr(writeAddress, iRgbBufNextLineOffs);
       
  1789 		}
       
  1790 	while (--vsf);
       
  1791 	}
       
  1792 
       
  1793 void CJpgReadCodec::WriteUnScaledMCU16M()
       
  1794 	{
       
  1795 	WriteUnScaledMCUImpl<TRawWriter>();
       
  1796 	}
       
  1797 
       
  1798 void CJpgReadCodec::WriteUnScaledMCU()
       
  1799 	{
       
  1800 	WriteUnScaledMCUImpl<TRgbWriter>();
       
  1801 	}
       
  1802 
       
  1803 template <class T>
       
  1804 inline void CJpgReadCodec::WriteUnScaledMCUImpl()
       
  1805 	{
       
  1806 	ASSERT((iScalingFactor == 1) || (iScalingFactor == -1));
       
  1807 
       
  1808 	TInt pixelsToSkip = GetMCURenderOffset() + iFirstPixelOffset;
       
  1809 	TRgb* writeAddress = T::ShiftPtr(iRgbBuffer, pixelsToSkip);
       
  1810 
       
  1811 	const TInt KYBlockOffset = KJpgDCTBlockWidth - (iFrameInfo.MCUWidthInPixels() * 8);
       
  1812 
       
  1813 	register const TInt ush = iHorzSampleRatioSh[KUShiftIdx];
       
  1814 	register const TInt vsh = iHorzSampleRatioSh[KVShiftIdx];
       
  1815 	const TInt16* yComp = iComponent[KYComp]->iCoeff;
       
  1816 	const TUVidxElemType* pixIdx = iUVIndeces;
       
  1817 
       
  1818 	TInt sf = iFrameInfo.MCUHeightInPixels();
       
  1819 	do
       
  1820 		{
       
  1821 		TInt hsf = iMaxHorzSampleFactor;
       
  1822 		do
       
  1823 			{
       
  1824 			const TInt16* const u_base = iComponent[KUComp]->iCoeff + *pixIdx++;
       
  1825 			const TInt16* const v_base = iComponent[KVComp]->iCoeff + *pixIdx++;
       
  1826 
       
  1827 #if defined(JPEG_OPTIMIZE_FOR_PERFORMCE)
       
  1828 
       
  1829 			T::WritePixel(writeAddress, *yComp++, u_base[0], v_base[0]);
       
  1830 			writeAddress = T::ShiftPtr(writeAddress, iPixelIncrement);
       
  1831 
       
  1832 			register TInt p=1;
       
  1833 
       
  1834 			T::WritePixel(writeAddress, *yComp++, u_base [(p>>ush)], v_base [(p>>vsh)]);
       
  1835 			writeAddress = T::ShiftPtr(writeAddress, iPixelIncrement);
       
  1836 			++p;
       
  1837 			T::WritePixel(writeAddress, *yComp++, u_base [(p>>ush)], v_base [(p>>vsh)]);
       
  1838 			writeAddress = T::ShiftPtr(writeAddress, iPixelIncrement);
       
  1839 			++p;
       
  1840 			T::WritePixel(writeAddress, *yComp++, u_base [(p>>ush)], v_base [(p>>vsh)]);
       
  1841 			writeAddress = T::ShiftPtr(writeAddress, iPixelIncrement);
       
  1842 			++p;
       
  1843 
       
  1844 			T::WritePixel(writeAddress, *yComp++, u_base [(p>>ush)], v_base [(p>>vsh)]);
       
  1845 			writeAddress = T::ShiftPtr(writeAddress, iPixelIncrement);
       
  1846 			++p;
       
  1847 			T::WritePixel(writeAddress, *yComp++, u_base [(p>>ush)], v_base [(p>>vsh)]);
       
  1848 			writeAddress = T::ShiftPtr(writeAddress, iPixelIncrement);
       
  1849 			++p;
       
  1850 			T::WritePixel(writeAddress, *yComp++, u_base [(p>>ush)], v_base [(p>>vsh)]);
       
  1851 			writeAddress = T::ShiftPtr(writeAddress, iPixelIncrement);
       
  1852 			++p;
       
  1853 			T::WritePixel(writeAddress, *yComp++, u_base [(p>>ush)], v_base [(p>>vsh)]);
       
  1854 			writeAddress = T::ShiftPtr(writeAddress, iPixelIncrement);
       
  1855 #else
       
  1856 
       
  1857 			register TInt p = 0;
       
  1858 			do
       
  1859 				{
       
  1860 				TInt y = *yComp++;
       
  1861 				TInt u = u_base[(p >> ush)];
       
  1862 				TInt v = v_base[(p >> vsh)];
       
  1863 
       
  1864 				T::WritePixel(writeAddress, y, u, v);
       
  1865 				writeAddress = T::ShiftPtr(writeAddress, iPixelIncrement);
       
  1866 				}
       
  1867 			while (++p < 8);
       
  1868 #endif
       
  1869 			yComp += (KJpgDCTBlockSize - KJpgDCTBlockWidth);
       
  1870 			}
       
  1871 		while (--hsf);
       
  1872 
       
  1873 		--sf;
       
  1874 		yComp += (sf & (KJpgDCTBlockWidth - 1)) ? KYBlockOffset : -(KJpgDCTBlockSize - KJpgDCTBlockWidth);
       
  1875 		writeAddress = T::ShiftPtr(writeAddress, iRgbBufNextLineOffs);
       
  1876 		}
       
  1877 	while (sf);
       
  1878 	}
       
  1879 
       
  1880 void CJpgReadCodec::WriteDiv2ScaledMCU()
       
  1881 	{
       
  1882 	WriteDiv2ScaledMCUImpl<TRgbWriter>();
       
  1883 	}
       
  1884 
       
  1885 void CJpgReadCodec::WriteDiv2ScaledMCU16M()
       
  1886 	{
       
  1887 	WriteDiv2ScaledMCUImpl<TRawWriter>();
       
  1888 	}
       
  1889 
       
  1890 template <class T>
       
  1891 inline void CJpgReadCodec::WriteDiv2ScaledMCUImpl()
       
  1892 	{
       
  1893 	ASSERT(iScalingFactor == -2);
       
  1894 
       
  1895 	const TInt KScalingFactor = 2;
       
  1896 	const TInt KYBlockOffset = KJpgDCTBlockWidth -
       
  1897 		(iMaxHorzSampleFactor * KJpgDCTBlockSize) +
       
  1898 		(KScalingFactor - 1) * KJpgDCTBlockWidth;
       
  1899 
       
  1900 	TInt pixelsToSkip = GetMCURenderOffset() + iFirstPixelOffset;
       
  1901 	TRgb* writeAddress = T::ShiftPtr(iRgbBuffer, pixelsToSkip);
       
  1902 
       
  1903 	const TInt16* yComp = iComponent[KYComp]->iCoeff;
       
  1904 	const TUVidxElemType* pixIdx = iUVIndeces;
       
  1905 	register const TInt ush = iHorzSampleRatioSh[KUShiftIdx];
       
  1906 	register const TInt vsh = iHorzSampleRatioSh[KVShiftIdx];
       
  1907 
       
  1908 	TInt sf = iMaxVertSampleFactor * KJpgDCTBlockWidth;
       
  1909 	/* Coverity may flag as overrun of array by accessing yComp. This is false positive. Coverity doesn't take into account that 
       
  1910 	iComponent[KYComp] can point to more than one TDataUnit.
       
  1911 	*/
       
  1912 	do
       
  1913 		{
       
  1914 		TInt hsf = iMaxHorzSampleFactor;
       
  1915 		do
       
  1916 			{
       
  1917 			const TInt16* const u_base = iComponent[KUComp]->iCoeff + *pixIdx++;
       
  1918 			const TInt16* const v_base = iComponent[KVComp]->iCoeff + *pixIdx++;
       
  1919 
       
  1920 			T::WritePixel(writeAddress, *yComp, u_base[0], v_base[0]);
       
  1921 			writeAddress = T::ShiftPtr(writeAddress, iPixelIncrement);
       
  1922 			yComp += KScalingFactor;
       
  1923 
       
  1924 			T::WritePixel(writeAddress, *yComp, u_base[KScalingFactor >> ush], v_base[KScalingFactor >> vsh]);
       
  1925 			writeAddress = T::ShiftPtr(writeAddress, iPixelIncrement);
       
  1926 			yComp += KScalingFactor;
       
  1927 
       
  1928 			T::WritePixel(writeAddress, *yComp, u_base[2 * KScalingFactor >> ush], v_base[2 * KScalingFactor >> vsh]);
       
  1929 			writeAddress = T::ShiftPtr(writeAddress, iPixelIncrement);
       
  1930 			yComp += KScalingFactor;
       
  1931 
       
  1932 			T::WritePixel(writeAddress, *yComp, u_base[3 * KScalingFactor >> ush], v_base[3 * KScalingFactor >> vsh]);
       
  1933 			writeAddress = T::ShiftPtr(writeAddress, iPixelIncrement);
       
  1934 			yComp += KScalingFactor + (KJpgDCTBlockSize - KJpgDCTBlockWidth);
       
  1935 			}
       
  1936 		while (--hsf);
       
  1937 
       
  1938 		sf -= KScalingFactor;
       
  1939 		yComp += (sf & (KJpgDCTBlockWidth-1))? KYBlockOffset: KScalingFactor*KJpgDCTBlockWidth-KJpgDCTBlockSize;
       
  1940 		writeAddress = T::ShiftPtr(writeAddress, iRgbBufNextLineOffs);
       
  1941 		}
       
  1942 	while (sf);
       
  1943 	}
       
  1944 
       
  1945 void CJpgReadCodec::WriteDiv4ScaledMCU()
       
  1946 	{
       
  1947 	WriteDiv4ScaledMCUImpl<TRgbWriter>();
       
  1948 	}
       
  1949 
       
  1950 void CJpgReadCodec::WriteDiv4ScaledMCU16M()
       
  1951 	{
       
  1952 	WriteDiv4ScaledMCUImpl<TRawInlineWriter>();
       
  1953 	}
       
  1954 
       
  1955 template <class T>
       
  1956 inline void CJpgReadCodec::WriteDiv4ScaledMCUImpl()
       
  1957 	{
       
  1958 	ASSERT(iScalingFactor == -3);
       
  1959 
       
  1960 	const TInt KScalingFactor = 4;
       
  1961 	const TInt KYBlockOffset = KJpgDCTBlockWidth -
       
  1962 		(iMaxHorzSampleFactor * KJpgDCTBlockSize) +
       
  1963 		(KScalingFactor - 1) * KJpgDCTBlockWidth;
       
  1964 
       
  1965 	TInt pixelsToSkip = GetMCURenderOffset() + iFirstPixelOffset;
       
  1966 	TRgb* writeAddress = T::ShiftPtr(iRgbBuffer, pixelsToSkip);
       
  1967 
       
  1968 	const TInt16* yComp = iComponent[KYComp]->iCoeff;
       
  1969 	const TUVidxElemType* pixIdx=iUVIndeces;
       
  1970 
       
  1971 	TInt sf = iMaxVertSampleFactor * KJpgDCTBlockWidth;
       
  1972 	/* Coverity may flag as overrun of array on accessing yComp. This is false positive. Coverity doesn't take into account that 
       
  1973 	iComponent[KYComp] can point to more than one TDataUnit.
       
  1974 	*/
       
  1975 	do
       
  1976 		{
       
  1977 		TInt hsf = iMaxHorzSampleFactor;
       
  1978 		do
       
  1979 			{
       
  1980 			const TInt16* const u_base1 = iComponent[KUComp]->iCoeff + *pixIdx;
       
  1981 			pixIdx++;
       
  1982 			const TInt16* const v_base1 = iComponent[KVComp]->iCoeff + *pixIdx;
       
  1983 			pixIdx++;
       
  1984 
       
  1985 			T::WritePixel(writeAddress, *yComp, u_base1[0], v_base1[0]);
       
  1986 			writeAddress = T::ShiftPtr(writeAddress, iPixelIncrement);
       
  1987 			yComp += KScalingFactor;
       
  1988 
       
  1989 			const TInt16 u_base2 = u_base1[*pixIdx];
       
  1990 			pixIdx++;
       
  1991 			const TInt16 v_base2 = v_base1[*pixIdx];
       
  1992 			pixIdx++;
       
  1993 
       
  1994 			T::WritePixel(writeAddress, *yComp, u_base2, v_base2);
       
  1995 			writeAddress = T::ShiftPtr(writeAddress, iPixelIncrement);
       
  1996 			yComp += KScalingFactor + (KJpgDCTBlockSize - KJpgDCTBlockWidth);
       
  1997 			}
       
  1998 		while (--hsf);
       
  1999 
       
  2000 		sf -= KScalingFactor;
       
  2001 		yComp += (sf & (KJpgDCTBlockWidth-1))? KYBlockOffset: KScalingFactor*KJpgDCTBlockWidth-KJpgDCTBlockSize;
       
  2002 		writeAddress = T::ShiftPtr(writeAddress, iRgbBufNextLineOffs);
       
  2003 		}
       
  2004 	while (sf);
       
  2005 	}
       
  2006 
       
  2007 
       
  2008 TInt CJpgReadCodec::ComponentIndexL(TInt aComponentId) const
       
  2009 	{
       
  2010 	for (TInt count = 0; count < iFrameInfo.iNumberOfComponents; count++)
       
  2011 		{
       
  2012 		if (iFrameInfo.iComponent[count].iId == aComponentId)
       
  2013 			return count;
       
  2014 		}
       
  2015 
       
  2016 	User::Leave(KErrCorrupt);
       
  2017 	return 0;
       
  2018 	}
       
  2019 
       
  2020 void CJpgReadCodec::SetYuvDecode(TBool aYuvDecode)
       
  2021 	{
       
  2022 	iYuvDecode = aYuvDecode;
       
  2023 	}
       
  2024 
       
  2025 void CJpgReadCodec::SetHighSpeedMode(TBool aHighSpeedMode)
       
  2026 	{
       
  2027 	iHighSpeedMode = aHighSpeedMode;
       
  2028 	}
       
  2029 
       
  2030 TInt CJpgReadCodec::RecommendBufferSizeL(TUid aFormatCode)
       
  2031 	{
       
  2032 	return CJpgImageFrameProcessorUtility::RecommendedBufferSizeL(iFrameInfo, aFormatCode);
       
  2033 	}
       
  2034 
       
  2035 void CJpgReadCodec::InitDrawFrame()
       
  2036 	{//default implementation do nothing
       
  2037 	}
       
  2038 
       
  2039 TBool CJpgReadCodec::DrawFrameL()
       
  2040 	{//default implementation do nothing
       
  2041 	return ETrue;
       
  2042 	}
       
  2043 
       
  2044 void CJpgReadCodec::CleanupBuffers()
       
  2045 	{//default implementation do nothing
       
  2046 	}
       
  2047 
       
  2048 void CJpgReadCodec::InitFrameHeader(TFrameInfo& aFrameInfo, CFrameImageData& /*aFrameData*/)
       
  2049 	{
       
  2050 	aFrameInfo.SetCurrentFrameState(TFrameInfo::EFrameInfoProcessingComplete);
       
  2051 	}
       
  2052 
       
  2053 
       
  2054 TInt CJpgReadCodec::MCUBlockPerRgbBuffer() const
       
  2055 	{
       
  2056 	return iMCUsPerBuffer;
       
  2057 	}
       
  2058 
       
  2059 TInt CJpgReadCodec::GetHorzMCUCount()
       
  2060 	{
       
  2061 	TInt maxMCUWidth = KJpgDCTBlockWidth * iMaxHorzSampleFactor;
       
  2062 	return (iFrameInfo.iSizeInPixels.iWidth + maxMCUWidth - 1) / maxMCUWidth;
       
  2063 	}
       
  2064 
       
  2065 TInt CJpgReadCodec::GetVertMCUCount()
       
  2066 	{
       
  2067 	TInt maxMCUHeight = KJpgDCTBlockWidth * iMaxVertSampleFactor;
       
  2068 	return (iFrameInfo.iSizeInPixels.iHeight + maxMCUHeight - 1) / maxMCUHeight;
       
  2069 	}
       
  2070 
       
  2071 //
       
  2072 // aExtensionManager is not owned.
       
  2073 //
       
  2074 void CJpgReadCodec::SetExtensionManager(CPluginExtensionManager* aExtensionManager)
       
  2075 	{
       
  2076 	iExtensionManager = aExtensionManager;
       
  2077 	}
       
  2078 
       
  2079 #if defined(__ARMCC__)
       
  2080 #pragma pop
       
  2081 #endif
       
  2082 
       
  2083 #if defined(__ARMCC__)
       
  2084 #pragma push
       
  2085 #pragma thumb
       
  2086 #endif
       
  2087 //
       
  2088 // CSequentialJpgReadCodec
       
  2089 CSequentialJpgReadCodec::CSequentialJpgReadCodec(
       
  2090 	const TJpgFrameInfo& aFrameInfo,
       
  2091 	const TJpgScanInfo& aScanInfo,
       
  2092 	TDecHuffmanTable aDCHuffmanTable[KJpgMaxNumberOfTables],
       
  2093 	TDecHuffmanTable aACHuffmanTable[KJpgMaxNumberOfTables],
       
  2094 	const TQTable aQTable[KJpgMaxNumberOfTables])
       
  2095  :	CJpgReadCodec(aFrameInfo, aScanInfo),
       
  2096 	iDCHuffmanTable(aDCHuffmanTable),
       
  2097 	iACHuffmanTable(aACHuffmanTable),
       
  2098 	iQTable(aQTable)
       
  2099 	{
       
  2100 	iProgressive = EFalse;
       
  2101 	}
       
  2102 
       
  2103 //
       
  2104 //
       
  2105 //
       
  2106 CSequentialJpgReadCodec::~CSequentialJpgReadCodec()
       
  2107 	{
       
  2108 	delete iMCUStore;
       
  2109 	iMCUStore = NULL;
       
  2110 
       
  2111 	User::Free(iMCULookup);
       
  2112 	iMCULookup = NULL;
       
  2113 	}
       
  2114 
       
  2115 //
       
  2116 //
       
  2117 //
       
  2118 CSequentialJpgReadCodec* CSequentialJpgReadCodec::NewL(
       
  2119 	const TJpgFrameInfo& aFrameInfo,
       
  2120 	const TJpgScanInfo& aScanInfo,
       
  2121 	TDecHuffmanTable aDCHuffmanTable[KJpgMaxNumberOfTables],
       
  2122 	TDecHuffmanTable aACHuffmanTable[KJpgMaxNumberOfTables],
       
  2123 	const TQTable aQTable[KJpgMaxNumberOfTables])
       
  2124 	{
       
  2125 	CSequentialJpgReadCodec* self = new(ELeave) CSequentialJpgReadCodec(
       
  2126 			aFrameInfo,
       
  2127 			aScanInfo,
       
  2128 			aDCHuffmanTable,
       
  2129 			aACHuffmanTable,
       
  2130 			aQTable);
       
  2131 	CleanupStack::PushL(self);
       
  2132 	self->ConstructL();
       
  2133 	CleanupStack::Pop(self);
       
  2134 	return self;
       
  2135 	}
       
  2136 
       
  2137 //
       
  2138 //
       
  2139 //
       
  2140 void CSequentialJpgReadCodec::ConstructL(TBool aUseCache)
       
  2141 	{
       
  2142 	CJpgReadCodec::ConstructL();
       
  2143 
       
  2144 	ASSERT(iMCULookup == NULL);
       
  2145 
       
  2146 	iTotalMCUCount = iFrameInfo.TotalMCUCount();
       
  2147 
       
  2148 	// Make sure iFrameInfo has had its members set.
       
  2149 	JPEG_ASSERT(iTotalMCUCount >= 1);
       
  2150 
       
  2151 	iMCUStore = CMCUStore::NewL(iFrameInfo);
       
  2152 
       
  2153 	// If the allocation of the lookup table fails, continue
       
  2154 	// to decode the image as it's not needed for some decodes
       
  2155 	// and others should be able to continue without it (with a
       
  2156 	// performance hit).
       
  2157 	if (aUseCache)
       
  2158 		{
       
  2159 		JPEG_DEBUG2(" - Cache for %d elements", iTotalMCUCount);
       
  2160 		TInt allocSize = iTotalMCUCount * sizeof(TMCUEntry);
       
  2161 		iMCULookup = reinterpret_cast<TMCUEntry*>(User::AllocZ(allocSize));
       
  2162 		}
       
  2163 	}
       
  2164 
       
  2165 //
       
  2166 // Nothing is guaranteed to be known about the image structure at this point.
       
  2167 //
       
  2168 void CSequentialJpgReadCodec::PreInitFrameL()
       
  2169 	{
       
  2170 	CJpgReadCodec::PreInitFrameL();
       
  2171 	iMCUStore->Reset();
       
  2172 	}
       
  2173 
       
  2174 
       
  2175 //
       
  2176 // This function is called after the various variants of
       
  2177 // InitFrameL have been called. At this stage enough should
       
  2178 // be known about the image to set several properties.
       
  2179 //
       
  2180 void CSequentialJpgReadCodec::PostInitFrameL()
       
  2181 	{
       
  2182 	iHorzMCUBlkCount = 0;
       
  2183 	iStreamMCU = 0;
       
  2184 	iMCUStore->SetMCUsPerBuffer(iMCUsPerBuffer);
       
  2185 	iMCUStore->SetOperation(iOperation);
       
  2186 	iNeededMCU = iMCUStore->GetNextMCU();
       
  2187 
       
  2188 	// Make sure iScanInfo isn't used before its members have been set.
       
  2189 	JPEG_ASSERT(iScanInfo.iImageOffset > 0);
       
  2190 
       
  2191 	iCurrentMCUBitOffset = (iScanInfo.iImageOffset * 8);
       
  2192 	
       
  2193 	CJpgReadCodec::PostInitFrameL();
       
  2194 	}
       
  2195 
       
  2196 //
       
  2197 // This is called by the framework whenever DoProcessL returns EFrameIncompleteRepositionRequest.
       
  2198 // After this function returns the framework should call DoProcessL again.
       
  2199 //
       
  2200 void CSequentialJpgReadCodec::GetNewDataPosition(TInt& aPosition, TInt& /*aLength*/)
       
  2201 	{
       
  2202 	if (!iMCULookup)
       
  2203 		{
       
  2204 		// Seek to the start of the image data.
       
  2205 		aPosition = iScanInfo.iImageOffset;
       
  2206 		iSeekDone = ETrue;
       
  2207 		return;
       
  2208 		}
       
  2209 
       
  2210 	if ((iNeededMCU >= 0) && (iNeededMCU < iTotalMCUCount))
       
  2211 		{
       
  2212 		TMCUEntry& entry = iMCULookup[iNeededMCU];
       
  2213 
       
  2214 		aPosition = (entry.iPosition >> 3);
       
  2215 		iSeekDone = ETrue;
       
  2216 		return;
       
  2217 		}
       
  2218 
       
  2219 	// The seek shouldn't have been made if iNeededMCU is outside
       
  2220 	// the bounds of the lookup table.
       
  2221 	ASSERT(EFalse);
       
  2222 	}
       
  2223 
       
  2224 #if defined(__ARMCC__)
       
  2225 #pragma pop
       
  2226 #endif
       
  2227 
       
  2228 #if defined(__ARMCC__)
       
  2229 // use ARM instruction for performance-critical code
       
  2230 #pragma push
       
  2231 #pragma arm 
       
  2232 #pragma O3 
       
  2233 #pragma Otime
       
  2234 #endif
       
  2235 //
       
  2236 // This will be called by CJpgReadCodec once enough
       
  2237 // data is available to do correct calculations.
       
  2238 //
       
  2239 void CSequentialJpgReadCodec::CalculateMCUBoundingRectL(TInt aMCUsPerLine)
       
  2240 	{
       
  2241 	JPEG_DEBUG1("CalculateMCUBoundingRectL()");
       
  2242 
       
  2243 	ASSERT(iExtensionManager);
       
  2244 
       
  2245 	JPEG_ASSERT(!iIsBlockStreaming);
       
  2246 	JPEG_ASSERT(!iProgressive);
       
  2247 	JPEG_ASSERT(aMCUsPerLine > 0);
       
  2248 
       
  2249 	TRect clipRect;
       
  2250 	clipRect = iExtensionManager->ClippingRect();
       
  2251 
       
  2252 	// This function shouldn't be called by InitFrameL
       
  2253 	// if no clipping rect has been set.
       
  2254 	JPEG_ASSERT(!clipRect.IsEmpty());
       
  2255 
       
  2256 	TInt mcuWidthInPixels = iFrameInfo.MCUWidthInPixels();
       
  2257 	TInt mcuHeightInPixels = iFrameInfo.MCUHeightInPixels();
       
  2258 	JPEG_DEBUG2(" - MCU pixel width: %d", mcuWidthInPixels);
       
  2259 	JPEG_DEBUG2(" - MCU pixel height: %d", mcuHeightInPixels);
       
  2260 
       
  2261 	// The clipping rect is specified in pixels. We need to
       
  2262 	// find out which MCUs contain these pixels.
       
  2263 	TInt left = clipRect.iTl.iX / mcuWidthInPixels;
       
  2264 	TInt top = clipRect.iTl.iY / mcuHeightInPixels;
       
  2265 	TInt right = (clipRect.iBr.iX - 1) / mcuWidthInPixels;
       
  2266 	TInt bottom = (clipRect.iBr.iY - 1) / mcuHeightInPixels;
       
  2267 
       
  2268 	TInt firstMCU = (top * aMCUsPerLine) + left;
       
  2269 
       
  2270 	iMCUClipRect.SetRect(left, top, right + 1, bottom + 1);
       
  2271 
       
  2272 	iMCUStore->SetClippingRect(firstMCU, iMCUClipRect.Width() * iMCUClipRect.Height());
       
  2273 
       
  2274 	// Convert back to pixels.
       
  2275 	left *= mcuWidthInPixels;
       
  2276 	top *= mcuHeightInPixels;
       
  2277 	right = (right * mcuWidthInPixels) + mcuWidthInPixels;
       
  2278 	bottom = (bottom * mcuHeightInPixels) + mcuHeightInPixels;
       
  2279 
       
  2280 	iMCUClipRect.SetRect(left, top, right, bottom);
       
  2281 	JPEG_DEBUG5("iMCUClipRect: (%d, %d) - (%d x %d)",
       
  2282 			iMCUClipRect.iTl.iX,
       
  2283 			iMCUClipRect.iTl.iY,
       
  2284 			iMCUClipRect.Width(),
       
  2285 			iMCUClipRect.Height());
       
  2286 	}
       
  2287 
       
  2288 //
       
  2289 //
       
  2290 //
       
  2291 void CSequentialJpgReadCodec::CacheMCULocation()
       
  2292 	{
       
  2293 	JPEG_ASSERT(iStreamMCU >= 0);
       
  2294 	JPEG_ASSERT(!iFrameInfo.iMultiScan);
       
  2295 
       
  2296 	if (!iMCULookup || (iStreamMCU >= iTotalMCUCount))
       
  2297 		{
       
  2298 		return;
       
  2299 		}
       
  2300 
       
  2301 	TMCUEntry& entry = iMCULookup[iStreamMCU];
       
  2302 
       
  2303 	if (entry.iPosition != 0)
       
  2304 		{
       
  2305 		for (TInt i = 0; i < 3; i++)
       
  2306 			{
       
  2307 			JPEG_ASSERT(entry.iDCPredictor[i] == iDCPredictor[i]);
       
  2308 			}
       
  2309 		}
       
  2310 	else
       
  2311 		{
       
  2312 		entry.iPosition = iCurrentMCUBitOffset;
       
  2313 		if (iEscapeAtEnd)
       
  2314 			{
       
  2315 			entry.iPosition -= 8;	// Go back a byte.
       
  2316 			}
       
  2317 
       
  2318 		entry.iDCPredictor[0] = iDCPredictor[0];
       
  2319 		entry.iDCPredictor[1] = iDCPredictor[1];
       
  2320 		entry.iDCPredictor[2] = iDCPredictor[2];
       
  2321 		entry.iRestartMCUCount = iRestartMCUCount;
       
  2322 		}
       
  2323 	}
       
  2324 
       
  2325 //
       
  2326 //
       
  2327 //
       
  2328 #ifdef JPEG_DEBUG_OUTPUT
       
  2329 void CSequentialJpgReadCodec::DumpCache()
       
  2330 	{
       
  2331 	JPEG_DEBUG1("CACHE DUMP");
       
  2332 	
       
  2333 	for (TInt i = 0; i < iTotalMCUCount; i++)
       
  2334 		{
       
  2335 		TMCUEntry& entry = iMCULookup[i];
       
  2336 		if (entry.iPosition == 0)
       
  2337 			{
       
  2338 			return;
       
  2339 			}
       
  2340 		
       
  2341 		JPEG_DEBUG7("Entry[%6d] location=%8d; predictors[%4d, %4d, %4d] restart=%d",
       
  2342 				i,
       
  2343 				entry.iPosition,
       
  2344 				entry.iDCPredictor[0],
       
  2345 				entry.iDCPredictor[1],
       
  2346 				entry.iDCPredictor[2],
       
  2347 				entry.iRestartMCUCount);
       
  2348 		}
       
  2349 	}
       
  2350 #endif
       
  2351 
       
  2352 //
       
  2353 // This is called after a seek has been performed.
       
  2354 // It sets everything up so that we're decoding from
       
  2355 // the correct position in the bitstream and does
       
  2356 // some other housekeeping.
       
  2357 //
       
  2358 void CSequentialJpgReadCodec::RestoreAfterSeekL()
       
  2359 	{
       
  2360 	// Reset the bitstream.
       
  2361 	TInt bitOffset = 0;
       
  2362 	iBitsLeft = 0;
       
  2363 	iBitBufferPtrLimit = 0;
       
  2364 	iDataValue = 0;
       
  2365 
       
  2366 	if (iMCULookup)
       
  2367 		{
       
  2368 		TMCUEntry& entry = iMCULookup[iNeededMCU];
       
  2369 
       
  2370 		// Divide entry.iPosition into byte and bit offsets.
       
  2371 		bitOffset = (entry.iPosition & 0x07);
       
  2372 
       
  2373 		// Make sure re-caching will work.
       
  2374 		iCurrentMCUBitOffset = entry.iPosition;
       
  2375 		iDCPredictor[0] = entry.iDCPredictor[0];
       
  2376 		iDCPredictor[1] = entry.iDCPredictor[1];
       
  2377 		iDCPredictor[2] = entry.iDCPredictor[2];
       
  2378 		iRestartMCUCount = entry.iRestartMCUCount;
       
  2379 
       
  2380 		iStreamMCU = iNeededMCU;
       
  2381 		}
       
  2382 	else
       
  2383 		{
       
  2384 		// The seek was to the start of the image.
       
  2385 		iRestartMCUCount = iFrameInfo.iRestartInterval;
       
  2386 		iDCPredictor[0] = 0;
       
  2387 		iDCPredictor[1] = 0;
       
  2388 		iDCPredictor[2] = 0;
       
  2389 		iStreamMCU = 0;
       
  2390 		iCurrentMCUBitOffset = iScanInfo.iImageOffset * 8;
       
  2391 		}
       
  2392 
       
  2393 	//FetchNext3BytesL();
       
  2394 	FillBitBufferL(iBitsLeft);
       
  2395 	iBitsLeft -= bitOffset;
       
  2396 	iSeekDone = EFalse;
       
  2397 	}
       
  2398 
       
  2399 
       
  2400 //
       
  2401 // Check's if the location of iNeededMCU is known in advance.
       
  2402 //
       
  2403 TBool CSequentialJpgReadCodec::QueryCache()
       
  2404 	{
       
  2405 	// Prevent an infinite seeking loop.
       
  2406 	if (iNeededMCU == iStreamMCU)
       
  2407 		{
       
  2408 		return EFalse;
       
  2409 		}
       
  2410 
       
  2411 	if (!iMCULookup)
       
  2412 		{
       
  2413 		if (iNeededMCU < iStreamMCU)
       
  2414 			{
       
  2415 			// We can seek to the start of the image and start
       
  2416 			// decoding again from there.
       
  2417 			iDataPtr++;
       
  2418 			return ETrue;
       
  2419 			}
       
  2420 
       
  2421 		return EFalse;
       
  2422 		}
       
  2423 
       
  2424 	if ((iNeededMCU < 0) || (iNeededMCU >= iTotalMCUCount))
       
  2425 		{
       
  2426 		// Out of bounds.
       
  2427 		return EFalse;
       
  2428 		}
       
  2429 
       
  2430 	TMCUEntry& entry = iMCULookup[iNeededMCU];
       
  2431 	if (entry.iPosition != 0)
       
  2432 		{
       
  2433 		// This is in order to get the framework to do the seek.
       
  2434 		iDataPtr++;
       
  2435 		return ETrue;
       
  2436 		}
       
  2437 
       
  2438 	return EFalse;
       
  2439 	}
       
  2440 
       
  2441 
       
  2442 #if defined(__ARMCC__)
       
  2443 #pragma pop 
       
  2444 #endif
       
  2445 
       
  2446 //
       
  2447 //
       
  2448 //
       
  2449 TFrameState CSequentialJpgReadCodec::DoProcessL()
       
  2450 	{
       
  2451 	if (iSeekDone)
       
  2452 		{
       
  2453 		RestoreAfterSeekL();
       
  2454 		}
       
  2455 
       
  2456 	while (iDataPtr < iDataPtrLimit)
       
  2457 		{
       
  2458 		if (iNeededMCU > iTotalMCUCount)
       
  2459 			{
       
  2460 			JPEG_LEAVE(KErrOverflow, "iNeededMCU is out of bounds");
       
  2461 			}
       
  2462 
       
  2463 		// See if we're done.
       
  2464 		if (iNeededMCU == KErrCompletion)
       
  2465 			{
       
  2466 			return EFrameComplete;
       
  2467 			}
       
  2468 		else if (QueryCache())
       
  2469 			{
       
  2470 			return EFrameIncompleteRepositionRequest;
       
  2471 			}
       
  2472 
       
  2473 		StoreState();
       
  2474 		if (iRestartMCUCount == 0)
       
  2475 			{
       
  2476 			TInt skipped = RestartStateL();
       
  2477 			iCurrentMCUBitOffset += (skipped * 8);
       
  2478 			}
       
  2479 
       
  2480 		CacheMCULocation();
       
  2481 
       
  2482 		TInt error = KErrNone;
       
  2483 		TInt mcuBitSize = 0;
       
  2484 		// we do that "if" in order to bypass exception handling which can
       
  2485 		// affect performance of the decoder
       
  2486 		if (iPreviousDataLeft < KMCUDataLeftThreshhold)
       
  2487 			{
       
  2488 			const TUint8* const latestDataPtr = iDataPtr;
       
  2489 			TRAP(error, mcuBitSize = ProcessMCUL());
       
  2490 
       
  2491 			// leave if it wasn't a partial MCU
       
  2492 			if ((error != KErrNone) &&
       
  2493 				(error != KErrEof ||
       
  2494 				latestDataPtr == iDataPtr ||
       
  2495 				(latestDataPtr + sizeof(TUint16) <= iDataPtrLimit &&
       
  2496 				PtrReadUtil::ReadBigEndianUint16(latestDataPtr) == KJpgEOISignature)))
       
  2497 				{
       
  2498 				User::Leave(error);
       
  2499 				}
       
  2500 			}
       
  2501 		else
       
  2502 			{
       
  2503 			mcuBitSize = ProcessMCUL();
       
  2504 			}
       
  2505 
       
  2506 		iCurrentMCUBitOffset += mcuBitSize;
       
  2507 
       
  2508 		// we would try to render the partially decoded MCU
       
  2509 		// in case if there is a partial MCU/incompelete image
       
  2510 		// and do leave with original error code later
       
  2511 		if (iStreamMCU == iNeededMCU)
       
  2512 			{
       
  2513 			if (iIsBlockStreaming &&
       
  2514 					(iNavigation == TDecodeStreamCaps::ENavigationRandomForward ||
       
  2515 					iNavigation == TDecodeStreamCaps::ENavigationRandomBackwards) &&
       
  2516 					iStreamMCU < iStreamDecodeConfig.iSeqPosition)
       
  2517 				{
       
  2518 				iNeededMCU = iMCUStore->GetNextMCU();
       
  2519 				}
       
  2520 			else
       
  2521 				{
       
  2522 				PostProcessMCUL(error != KErrNone);
       
  2523 
       
  2524 				User::LeaveIfError(error);
       
  2525 
       
  2526 				if (iIsBlockStreaming)
       
  2527 					{
       
  2528 					iNeededMCU++;
       
  2529 					if (EBlockComplete == ProcessStreaming())
       
  2530 						{
       
  2531 						iStreamMCU++;
       
  2532 						iRestartMCUCount--;
       
  2533 						return EBlockComplete;
       
  2534 						}
       
  2535 					}
       
  2536 				else
       
  2537 					{
       
  2538 					iNeededMCU = iMCUStore->GetNextMCU();
       
  2539 					}
       
  2540 				}
       
  2541 			}
       
  2542 
       
  2543 		iStreamMCU++;
       
  2544 		iRestartMCUCount--;
       
  2545 
       
  2546 		TInt dataLeft = iDataPtrLimit - iDataPtr;
       
  2547 		if (dataLeft < KMCUDataLeftThreshhold)
       
  2548 			{
       
  2549 			TBool needLeave = (iPreviousDataLeft > dataLeft);
       
  2550 			iPreviousDataLeft = dataLeft;
       
  2551 			if (needLeave)
       
  2552 				{
       
  2553 				StoreState();
       
  2554 				User::Leave(KErrCompletion);
       
  2555 				}
       
  2556 			}
       
  2557 		}
       
  2558 
       
  2559 	return EFrameIncomplete;
       
  2560 	}
       
  2561 
       
  2562 TFrameState CSequentialJpgReadCodec::ProcessStreaming()
       
  2563 	{
       
  2564 	if(iNavigation == TDecodeStreamCaps::ENavigationSequentialForward)
       
  2565 		{
       
  2566 		if(iTotalMCUCount > iNeededMCU)
       
  2567 			{
       
  2568 			*(iStreamDecodeConfig.iHaveMoreBlocks) = ETrue;
       
  2569 			}
       
  2570 		else
       
  2571 			{
       
  2572 			*(iStreamDecodeConfig.iHaveMoreBlocks) = EFalse;
       
  2573 			}
       
  2574 		}
       
  2575 
       
  2576 	*(iStreamDecodeConfig.iNumBlocksRead) += 1;
       
  2577 
       
  2578 	if(*(iStreamDecodeConfig.iNumBlocksRead) >= iStreamDecodeConfig.iNumBlocksToGet)
       
  2579 		{
       
  2580 		return EBlockComplete;
       
  2581 		}
       
  2582 	else
       
  2583 		{
       
  2584 		return EFrameIncomplete;
       
  2585 		}
       
  2586 	}
       
  2587 
       
  2588 //
       
  2589 // This functions turns the MCU data into pixel data.
       
  2590 // The pixel data is written into an intermediate buffer,
       
  2591 // iRgbBuffer, by WriteMCU() and then if this intermediate
       
  2592 // buffer is full this is copied to the output bitmap by
       
  2593 // SetPixelBlock().
       
  2594 //
       
  2595 void CSequentialJpgReadCodec::PostProcessMCUL(TBool aForceBufferFlush)
       
  2596 	{
       
  2597 	if (!iImageFrameCodecPtr)
       
  2598 		{
       
  2599 		TBool copyIt = aForceBufferFlush;
       
  2600 
       
  2601 		WriteMCU();
       
  2602 		iHorzMCUBlkCount++;
       
  2603 
       
  2604 		// Only copy the buffer if we have rendered a row of MCUs or are forced to.
       
  2605 		copyIt |= (iHorzMCUBlkCount == iMCUsPerBuffer);
       
  2606 		if (copyIt)
       
  2607 			{
       
  2608 			CImageProcessor* proc = ImageProcessor();
       
  2609 			ASSERT(proc != NULL);
       
  2610 			proc->SetPixelBlock(iRgbBuffer);
       
  2611 			iMCUStore->NextLine();
       
  2612 			iHorzMCUBlkCount = 0;
       
  2613 			}
       
  2614 		}
       
  2615 	else
       
  2616 		{
       
  2617 		RArray<const TDataUnit*> dataUnits;
       
  2618 		CleanupClosePushL(dataUnits);
       
  2619 		for(TInt i = 0; i < iFrameInfo.iNumberOfComponents; i++)
       
  2620 			{
       
  2621 			TDataUnit* compPtr = iComponent[i];
       
  2622 			TInt numSamples = iMCUDataUnitCount[i];
       
  2623 			while (numSamples > 0)
       
  2624 				{
       
  2625 				numSamples--;
       
  2626 				User::LeaveIfError(dataUnits.Append(compPtr++));
       
  2627 				}
       
  2628 			}
       
  2629 		iImageFrameCodecPtr->ProcessL(dataUnits);
       
  2630 		CleanupStack::PopAndDestroy(1, &dataUnits);
       
  2631 		}
       
  2632 	}
       
  2633 
       
  2634 
       
  2635 TInt CSequentialJpgReadCodec::ProcessMCUL()
       
  2636 	{
       
  2637 	TDataUnit temp;
       
  2638 	TInt numValues;
       
  2639 	TInt bitsBefore = iBitsLeft;
       
  2640 	const TUint8* startPtr = iDataPtr;
       
  2641 	
       
  2642 	iEscapeAtEnd = EFalse;
       
  2643 	for (TInt i = 0; i < iScanInfo.iNumberOfComponents; i++)
       
  2644 		{
       
  2645 		TJpgScanInfo::TScanComponentInfo& scanInfo = iScanInfo.iComponent[i];
       
  2646 		TInt compIndex = ComponentIndexL(scanInfo.iId);
       
  2647 		TJpgFrameInfo::TComponentInfo& compInfo = iFrameInfo.iComponent[compIndex];
       
  2648 		const TDecHuffmanTable& dcTable = iDCHuffmanTable[scanInfo.iDCCodingTable];
       
  2649 		const TDecHuffmanTable& acTable = iACHuffmanTable[scanInfo.iACCodingTable];
       
  2650 		const TQTable& qTable = iQTable[compInfo.iQTable];
       
  2651 		TDataUnit* compPtr = iComponent[compIndex];
       
  2652 		if (compPtr==NULL)
       
  2653 			{
       
  2654 			compPtr = &temp; // we'd throw it away in case of Mono mode
       
  2655 			}
       
  2656 		TInt numSamples = iMCUDataUnitCount[compIndex];
       
  2657 
       
  2658 		while (numSamples > 0)
       
  2659 			{
       
  2660 			GetComponentBlockL(*compPtr, numValues, iDCPredictor[compIndex], dcTable, acTable);
       
  2661 			if (compIndex == 0 || !iMonochrome)
       
  2662 				{
       
  2663 				(qTable.*iCompConf[compIndex].iDequantFunc)(temp, *compPtr, numValues);
       
  2664 				iCompConf[compIndex].iDCT->InverseTransform(*compPtr, temp);
       
  2665 				compPtr++;
       
  2666 				}
       
  2667 			numSamples--;
       
  2668 			}
       
  2669 		}
       
  2670 	
       
  2671 	if (iRestartMCUCount == 1)
       
  2672 		{
       
  2673 		iBitsLeft = 0;
       
  2674 		}
       
  2675 	else
       
  2676 		{
       
  2677 		iEscapeAtEnd = ((iDataValue & 0xFF) == 0xFF);
       
  2678 		}
       
  2679 
       
  2680 	TInt bytesRead = iDataPtr - startPtr;
       
  2681 	return bitsBefore + (bytesRead * 8) - iBitsLeft;
       
  2682 	}
       
  2683 
       
  2684 
       
  2685 #if defined(__ARMCC__)
       
  2686 // use ARM instruction for performance-critical code
       
  2687 #pragma push
       
  2688 #pragma thumb 
       
  2689 #endif
       
  2690 
       
  2691 // CProgressiveJpgReadCodec
       
  2692 CProgressiveJpgReadCodec::CProgressiveJpgReadCodec(const TJpgFrameInfo& aFrameInfo,const TJpgScanInfo& aScanInfo,const TDecHuffmanTable aDCHuffmanTable[KJpgMaxNumberOfTables],const TDecHuffmanTable aACHuffmanTable[KJpgMaxNumberOfTables],const TQTable aQTable[KJpgMaxNumberOfTables])
       
  2693 :	CJpgReadCodec(aFrameInfo,aScanInfo),
       
  2694 	iOriginalFrameInfo(aFrameInfo),
       
  2695 	iOriginalScanInfo(aScanInfo)
       
  2696 	{
       
  2697 	iProgressive = ETrue;
       
  2698 	Mem::Copy(iDCHuffmanTable,aDCHuffmanTable,sizeof(TDecHuffmanTable) * KJpgMaxNumberOfTables);
       
  2699 	Mem::Copy(iACHuffmanTable,aACHuffmanTable,sizeof(TDecHuffmanTable) * KJpgMaxNumberOfTables);
       
  2700 	Mem::Copy(iQTable,aQTable,sizeof(TQTable) * KJpgMaxNumberOfTables);
       
  2701 	}
       
  2702 
       
  2703 CProgressiveJpgReadCodec* CProgressiveJpgReadCodec::NewL(const TJpgFrameInfo& aFrameInfo,const TJpgScanInfo& aScanInfo,const TDecHuffmanTable aDCHuffmanTable[KJpgMaxNumberOfTables],const TDecHuffmanTable aACHuffmanTable[KJpgMaxNumberOfTables],const TQTable aQTable[KJpgMaxNumberOfTables])
       
  2704 	{
       
  2705 	CProgressiveJpgReadCodec* self = new(ELeave) CProgressiveJpgReadCodec(aFrameInfo, aScanInfo, aDCHuffmanTable, aACHuffmanTable, aQTable);
       
  2706 	CleanupStack::PushL(self);
       
  2707 	self->ConstructL();
       
  2708 	CleanupStack::Pop(self);
       
  2709 	return self;
       
  2710 	}
       
  2711 
       
  2712 CProgressiveJpgReadCodec::~CProgressiveJpgReadCodec()
       
  2713 	{
       
  2714 	CleanupBuffers();
       
  2715 	}
       
  2716 
       
  2717 void CProgressiveJpgReadCodec::DoInitFrameL()
       
  2718 	{
       
  2719 	iFrameInfo = iOriginalFrameInfo;
       
  2720 	iScanInfo = iOriginalScanInfo;
       
  2721 
       
  2722 	TInt maxMCUWidth = KJpgDCTBlockWidth * iMaxHorzSampleFactor;
       
  2723 	TInt maxMCUHeight = KJpgDCTBlockWidth * iMaxVertSampleFactor;
       
  2724 	iHorzMCUCount = (iFrameInfo.iSizeInPixels.iWidth + maxMCUWidth - 1) / maxMCUWidth;
       
  2725 	iVertMCUCount = (iFrameInfo.iSizeInPixels.iHeight + maxMCUHeight - 1) / maxMCUHeight;
       
  2726 	iTotalMCUCount = iHorzMCUCount * iVertMCUCount;
       
  2727 	iCurrentMCUCount = 0;
       
  2728 	iCurrentMCUHorzCount = 0;
       
  2729 	iCurrentMCUVertCount = 0;
       
  2730 	iMCUChunkAllocated = EFalse;
       
  2731 
       
  2732 	// We calculate how many data units we'll need in total
       
  2733 	TInt totalDataUnitCount = 0;
       
  2734 	for (TInt compIndex = 0; compIndex < iFrameInfo.iNumberOfComponents; compIndex++)
       
  2735 		{
       
  2736 		totalDataUnitCount += iMCUDataUnitCount[compIndex] * iTotalMCUCount;
       
  2737 		}
       
  2738 
       
  2739 	TUint8* offset = NULL;
       
  2740 	if(totalDataUnitCount > KMCUMaxTotalDataUnits)
       
  2741 		{
       
  2742  		iMCUChunk.Close();
       
  2743 		User::LeaveIfError(iMCUChunk.CreateLocal(totalDataUnitCount * sizeof(TDataUnit), totalDataUnitCount * sizeof(TDataUnit)));
       
  2744 		offset = iMCUChunk.Base();
       
  2745 		iMCUChunkAllocated = ETrue;
       
  2746 		}
       
  2747     else
       
  2748         {
       
  2749         delete iMCUMemoryBuffer;
       
  2750         iMCUMemoryBuffer = NULL;
       
  2751         iMCUMemoryBuffer = new (ELeave) TUint8 [ totalDataUnitCount * sizeof(TDataUnit) ];
       
  2752         offset = iMCUMemoryBuffer;
       
  2753         }
       
  2754 
       
  2755 
       
  2756 	for (TInt compIndex = 0; compIndex < iFrameInfo.iNumberOfComponents; compIndex++)
       
  2757 		{
       
  2758 		TInt dataUnitCount = iMCUDataUnitCount[compIndex] * iTotalMCUCount;
       
  2759 
       
  2760 		iMCUBuffer[compIndex] = new(offset) TDataUnit[dataUnitCount];
       
  2761 		offset += dataUnitCount * sizeof(TDataUnit);
       
  2762 
       
  2763 		Mem::FillZ(iMCUBuffer[compIndex],dataUnitCount * sizeof(TDataUnit));
       
  2764 		iMCUBufferPtr[compIndex] = iMCUBuffer[compIndex];
       
  2765 		iMCUBufferPtrLimit[compIndex] = iMCUBuffer[compIndex] + dataUnitCount;
       
  2766 
       
  2767 		iIndividualHorzMCUCount[compIndex] = ((iFrameInfo.iSizeInPixels.iWidth*iHorzSampleFactor[compIndex]) + maxMCUWidth - 1) / maxMCUWidth;
       
  2768 		iIndividualVertMCUCount[compIndex] = ((iFrameInfo.iSizeInPixels.iHeight*iVertSampleFactor[compIndex]) + maxMCUHeight - 1) / maxMCUHeight;
       
  2769 		}
       
  2770 
       
  2771 	iProcessing = ETrue;
       
  2772 	iRefinedDCValue = 0;
       
  2773 	}
       
  2774 
       
  2775 //
       
  2776 // Progressive supports scaling and normal decode only.
       
  2777 //
       
  2778 void CProgressiveJpgReadCodec::PreInitFrameL()
       
  2779 	{
       
  2780 	CJpgReadCodec::PreInitFrameL();
       
  2781 	
       
  2782 	if (iOperation != EDecodeNormal)
       
  2783 		{
       
  2784 		JPEG_LEAVE(KErrNotSupported, "No operations on Progressive");
       
  2785 		}
       
  2786 	
       
  2787 	if (iUseClipRect)
       
  2788 		{
       
  2789 		JPEG_LEAVE(KErrNotSupported, "No clipping on Progressive");
       
  2790 		}
       
  2791 	}
       
  2792 
       
  2793 void CProgressiveJpgReadCodec::InitFrameL(TFrameInfo& aFrameInfo, CFrameImageData& aFrameImageData, TBool aDisableErrorDiffusion, CFbsBitmap& aFrame, CFbsBitmap* aFrameMask)
       
  2794 	{
       
  2795 	CJpgReadCodec::InitFrameL(aFrameInfo, aFrameImageData, aDisableErrorDiffusion, aFrame, aFrameMask);
       
  2796 
       
  2797 	ClearBitmapL(aFrame, KRgbWhite); // clear bitmap so sensibly draw partial decodes
       
  2798 
       
  2799 	DoInitFrameL();
       
  2800 	}
       
  2801 
       
  2802 void CProgressiveJpgReadCodec::InitFrameL(CImageFrame& aFrame)
       
  2803 	{
       
  2804 	CJpgReadCodec::InitFrameL(aFrame);
       
  2805 
       
  2806 	DoInitFrameL();
       
  2807 	}
       
  2808 
       
  2809 #if defined(__ARMCC__)
       
  2810 #pragma pop 
       
  2811 #endif
       
  2812 
       
  2813 TFrameState CProgressiveJpgReadCodec::DoProcessL()
       
  2814 	{
       
  2815 	FOREVER
       
  2816 		{
       
  2817 		if (iProcessing)
       
  2818 			ProcessFrameL();
       
  2819 		else
       
  2820 			{
       
  2821 			StoreState();
       
  2822 			TInt dataRemaining = iDataPtrLimit - iDataPtr;
       
  2823 			if (dataRemaining < 2)
       
  2824 				return EFrameIncomplete;
       
  2825 
       
  2826 			TInt sig = (iDataPtr[0] << 8) | iDataPtr[1];
       
  2827 			switch (sig)
       
  2828 				{
       
  2829 			case KJpgDHTSignature:
       
  2830 				LoadHuffmanTableL();
       
  2831 				break;
       
  2832 			case KJpgDQTSignature:
       
  2833 				break;
       
  2834 			case KJpgSOSSignature:
       
  2835 				LoadSOSL();
       
  2836 				iProcessing = ETrue;
       
  2837 				break;
       
  2838 			case KJpgRestartIntervalSignature:
       
  2839 				LoadRestartIntervalL();
       
  2840 				break;
       
  2841 			case KJpgEOISignature:
       
  2842 				iDataPtr += 2;
       
  2843 				return EFrameComplete;
       
  2844 			default:
       
  2845 #if defined(RELAX_JPEG_STRICTNESS)
       
  2846 				iDataPtr += 1;
       
  2847 				dataRemaining = iDataPtrLimit - iDataPtr;
       
  2848 				if (dataRemaining < 2)
       
  2849 					{
       
  2850 					return EFrameIncomplete;
       
  2851 					}
       
  2852 #else
       
  2853 				User::Leave(KErrCorrupt);
       
  2854 #endif
       
  2855 				break;
       
  2856 				}
       
  2857 			}
       
  2858 		}
       
  2859 	}
       
  2860 
       
  2861 void CProgressiveJpgReadCodec::ProcessFrameL()
       
  2862 	{
       
  2863 	if (iScanInfo.iEndSpectralSelection == 0)
       
  2864 		{
       
  2865 		if (iScanInfo.iSuccessiveApproximationBitsHigh == 0)
       
  2866 			InitDCL();
       
  2867 		else
       
  2868 			RefineDCL();
       
  2869 		}
       
  2870 	else
       
  2871 		{
       
  2872 		if (iScanInfo.iSuccessiveApproximationBitsHigh == 0)
       
  2873 			InitACL();
       
  2874 		else
       
  2875 			RefineACL();
       
  2876 		}
       
  2877 	}
       
  2878 
       
  2879 void CProgressiveJpgReadCodec::InitDCL()
       
  2880 	{
       
  2881 	if(iScanInfo.iNumberOfComponents == 1)
       
  2882 		{ //Non interleaved scan
       
  2883 		for (TInt scanInfoIndex = 0; scanInfoIndex < iScanInfo.iNumberOfComponents; scanInfoIndex++)
       
  2884 			{
       
  2885 			TJpgScanInfo::TScanComponentInfo& scanInfo = iScanInfo.iComponent[scanInfoIndex];
       
  2886 			TInt compIndex = ComponentIndexL(scanInfo.iId);
       
  2887 			const TDecHuffmanTable& dcTable = iDCHuffmanTable[scanInfo.iDCCodingTable];
       
  2888 			TInt& dcPredictor = iDCPredictor[compIndex];
       
  2889 			TInt dataUnitCount = iMCUDataUnitCount[compIndex];
       
  2890 
       
  2891 			TInt horzSamples = iHorzSampleFactor[compIndex];
       
  2892 			TInt vertSamples = iVertSampleFactor[compIndex];
       
  2893 			TDataUnit* dataUnit = iMCUBuffer[compIndex];
       
  2894 			for (; iCurrentMCUVertCount < iIndividualVertMCUCount[compIndex]; iCurrentMCUVertCount++)
       
  2895 				{
       
  2896 				TInt blockBase = (iCurrentMCUVertCount / vertSamples) * iHorzMCUCount;
       
  2897 				TInt unitBase = (iCurrentMCUVertCount % vertSamples) * horzSamples;
       
  2898 				for (; iCurrentMCUHorzCount < iIndividualHorzMCUCount[compIndex]; iCurrentMCUHorzCount++)
       
  2899 					{
       
  2900 					StoreState();
       
  2901 					if (iRestartMCUCount == 0)
       
  2902 						RestartStateL();
       
  2903 
       
  2904 					TInt blockOffset = blockBase + (iCurrentMCUHorzCount / horzSamples);
       
  2905 					TInt unitOffset = unitBase + (iCurrentMCUHorzCount % horzSamples);
       
  2906 
       
  2907 					GetDCValueL(dataUnit[(blockOffset * dataUnitCount) + unitOffset],dcTable,dcPredictor);
       
  2908 
       
  2909 					iRestartMCUCount--;
       
  2910 					}
       
  2911 
       
  2912 				iCurrentMCUHorzCount = 0;
       
  2913 				}
       
  2914 			iCurrentMCUVertCount = 0;
       
  2915 			}
       
  2916 		}
       
  2917 	else
       
  2918 		{ // Interleaved scan
       
  2919 		for(; iCurrentMCUCount < iTotalMCUCount; iCurrentMCUCount++)
       
  2920 			{
       
  2921 			StoreState();
       
  2922 			if (iRestartMCUCount == 0)
       
  2923 				RestartStateL();
       
  2924 
       
  2925 			for (TInt scanInfoIndex = 0; scanInfoIndex < iScanInfo.iNumberOfComponents; scanInfoIndex++)
       
  2926 				{
       
  2927 				TJpgScanInfo::TScanComponentInfo& scanInfo = iScanInfo.iComponent[scanInfoIndex];
       
  2928 				TInt compIndex = ComponentIndexL(scanInfo.iId);
       
  2929 				const TDecHuffmanTable& dcTable = iDCHuffmanTable[scanInfo.iDCCodingTable];
       
  2930 				TInt& dcPredictor = iDCPredictor[compIndex];
       
  2931 				TDataUnit* tempMCUBufferPtr = iMCUBufferPtr[compIndex];
       
  2932 
       
  2933 				for (TInt count = iMCUDataUnitCount[compIndex]; count > 0; count--)
       
  2934 					{
       
  2935 					GetDCValueL(*tempMCUBufferPtr,dcTable,dcPredictor);
       
  2936 					tempMCUBufferPtr++;
       
  2937 					}
       
  2938 				}
       
  2939 
       
  2940 			for (TInt count = 0; count < iFrameInfo.iNumberOfComponents; count++)
       
  2941 				iMCUBufferPtr[count] += iMCUDataUnitCount[count];
       
  2942 
       
  2943 			iRestartMCUCount--;
       
  2944 			}
       
  2945 		}
       
  2946 
       
  2947 	for (TInt count = 0; count < iFrameInfo.iNumberOfComponents; count++)
       
  2948 		iMCUBufferPtr[count] = iMCUBuffer[count];
       
  2949 
       
  2950 	ResetState();
       
  2951 	iCurrentMCUCount = 0;
       
  2952 	iProcessing = EFalse;
       
  2953 	}
       
  2954 
       
  2955 void CProgressiveJpgReadCodec::RefineDCL()
       
  2956 	{
       
  2957 	for(; iCurrentMCUCount < iTotalMCUCount; iCurrentMCUCount++)
       
  2958 		{
       
  2959 		StoreState();
       
  2960 		if (iRestartMCUCount == 0)
       
  2961 			RestartStateL();
       
  2962 
       
  2963 		for (TInt scanInfoIndex = 0; scanInfoIndex < iScanInfo.iNumberOfComponents; scanInfoIndex++)
       
  2964 			{
       
  2965 			TJpgScanInfo::TScanComponentInfo& scanInfo = iScanInfo.iComponent[scanInfoIndex];
       
  2966 			TInt compIndex = ComponentIndexL(scanInfo.iId);
       
  2967 			TDataUnit* tempMCUBufferPtr = iMCUBufferPtr[compIndex];
       
  2968 
       
  2969 			for (TInt count = iMCUDataUnitCount[compIndex]; count > 0; count--)
       
  2970 				{
       
  2971 				if (NextBitL())
       
  2972 					tempMCUBufferPtr->iCoeff[0] |= iRefinedDCValue;
       
  2973 				tempMCUBufferPtr++;
       
  2974 				}
       
  2975 			}
       
  2976 
       
  2977 		for (TInt count = 0; count < iFrameInfo.iNumberOfComponents; count++)
       
  2978 			iMCUBufferPtr[count] += iMCUDataUnitCount[count];
       
  2979 
       
  2980 		iRestartMCUCount--;
       
  2981 		}
       
  2982 
       
  2983 	for (TInt count = 0; count < iFrameInfo.iNumberOfComponents; count++)
       
  2984 		iMCUBufferPtr[count] = iMCUBuffer[count];
       
  2985 
       
  2986 	ResetState();
       
  2987 	iCurrentMCUCount = 0;
       
  2988 	iProcessing = EFalse;
       
  2989 	}
       
  2990 
       
  2991 void CProgressiveJpgReadCodec::InitACL()
       
  2992 	{
       
  2993 	if (iScanInfo.iNumberOfComponents > 1)
       
  2994 		User::Leave(KErrCorrupt);
       
  2995 
       
  2996 	TInt compIndex = ComponentIndexL(iScanInfo.iComponent[0].iId);
       
  2997 	const TDecHuffmanTable& acTable = iACHuffmanTable[iScanInfo.iComponent[0].iACCodingTable];
       
  2998 	TInt dataUnitCount = iMCUDataUnitCount[compIndex];
       
  2999 
       
  3000 	if (dataUnitCount == 1)
       
  3001 		{
       
  3002 		for(; iCurrentMCUCount < iTotalMCUCount; iCurrentMCUCount++)
       
  3003 			{
       
  3004 			StoreState();
       
  3005 			if (iRestartMCUCount == 0)
       
  3006 				RestartStateL();
       
  3007 
       
  3008 			if (iSkipCount == 0)
       
  3009 				iSkipCount = GetACValuesL(*iMCUBufferPtr[compIndex],acTable);
       
  3010 			else
       
  3011 				iSkipCount--;
       
  3012 
       
  3013 			iMCUBufferPtr[compIndex]++;
       
  3014 			iRestartMCUCount--;
       
  3015 			}
       
  3016 
       
  3017 		iCurrentMCUCount = 0;
       
  3018 		}
       
  3019 	else
       
  3020 		{
       
  3021 		TInt horzSamples = iHorzSampleFactor[compIndex];
       
  3022 		TInt vertSamples = iVertSampleFactor[compIndex];
       
  3023 		TDataUnit* dataUnit = iMCUBuffer[compIndex];
       
  3024 		for (; iCurrentMCUVertCount < iIndividualVertMCUCount[compIndex]; iCurrentMCUVertCount++)
       
  3025 			{
       
  3026 			TInt blockBase = (iCurrentMCUVertCount / vertSamples) * iHorzMCUCount;
       
  3027 			TInt unitBase = (iCurrentMCUVertCount % vertSamples) * horzSamples;
       
  3028 			for (; iCurrentMCUHorzCount < iIndividualHorzMCUCount[compIndex]; iCurrentMCUHorzCount++)
       
  3029 				{
       
  3030 				StoreState();
       
  3031 				if (iRestartMCUCount == 0)
       
  3032 					RestartStateL();
       
  3033 
       
  3034 				if (iSkipCount == 0)
       
  3035 					{
       
  3036 					TInt blockOffset = blockBase + (iCurrentMCUHorzCount / horzSamples);
       
  3037 					TInt unitOffset = unitBase + (iCurrentMCUHorzCount % horzSamples);
       
  3038 					iSkipCount = GetACValuesL(dataUnit[(blockOffset * dataUnitCount) + unitOffset],acTable);
       
  3039 					}
       
  3040 				else
       
  3041 					iSkipCount--;
       
  3042 
       
  3043 				iRestartMCUCount--;
       
  3044 				}
       
  3045 
       
  3046 			iCurrentMCUHorzCount = 0;
       
  3047 			}
       
  3048 		iCurrentMCUVertCount = 0;
       
  3049 		}
       
  3050 
       
  3051 	for (TInt count = 0; count < iFrameInfo.iNumberOfComponents; count++)
       
  3052 		iMCUBufferPtr[count] = iMCUBuffer[count];
       
  3053 
       
  3054 	iSkipCount = 0;
       
  3055 	ResetState();
       
  3056 	iProcessing = EFalse;
       
  3057 	}
       
  3058 
       
  3059 void CProgressiveJpgReadCodec::RefineACL()
       
  3060 	{
       
  3061 	if (iScanInfo.iNumberOfComponents > 1)
       
  3062 		User::Leave(KErrCorrupt);
       
  3063 
       
  3064 	TInt compIndex = ComponentIndexL(iScanInfo.iComponent[0].iId);
       
  3065 	const TDecHuffmanTable& acTable = iACHuffmanTable[iScanInfo.iComponent[0].iACCodingTable];
       
  3066 	TInt dataUnitCount = iMCUDataUnitCount[compIndex];
       
  3067 	if (dataUnitCount == 1)
       
  3068 		{
       
  3069 		for(; iCurrentMCUCount < iTotalMCUCount; iCurrentMCUCount++)
       
  3070 			{
       
  3071 			StoreState();
       
  3072 			if (iRestartMCUCount == 0)
       
  3073 				RestartStateL();
       
  3074 
       
  3075 			RefineACValuesL(*iMCUBufferPtr[compIndex],acTable);
       
  3076 			iMCUBufferPtr[compIndex]++;
       
  3077 
       
  3078 			iRestartMCUCount--;
       
  3079 			}
       
  3080 
       
  3081 		iCurrentMCUCount = 0;
       
  3082 		}
       
  3083 	else
       
  3084 		{
       
  3085 		TInt horzSamples = iHorzSampleFactor[compIndex];
       
  3086 		TInt vertSamples = iVertSampleFactor[compIndex];
       
  3087 		TDataUnit* dataUnit = iMCUBuffer[compIndex];
       
  3088 		for (; iCurrentMCUVertCount < iIndividualVertMCUCount[compIndex]; iCurrentMCUVertCount++)
       
  3089 			{
       
  3090 			TInt blockBase = (iCurrentMCUVertCount / vertSamples) * iHorzMCUCount;
       
  3091 			TInt unitBase = (iCurrentMCUVertCount % vertSamples) * horzSamples;
       
  3092 			for (; iCurrentMCUHorzCount < iIndividualHorzMCUCount[compIndex]; iCurrentMCUHorzCount++)
       
  3093 				{
       
  3094 				StoreState();
       
  3095 				if (iRestartMCUCount == 0)
       
  3096 					RestartStateL();
       
  3097 
       
  3098 				TInt blockOffset = blockBase + (iCurrentMCUHorzCount / horzSamples);
       
  3099 				TInt unitOffset = unitBase + (iCurrentMCUHorzCount % horzSamples);
       
  3100 				RefineACValuesL(dataUnit[(blockOffset * dataUnitCount) + unitOffset],acTable);
       
  3101 
       
  3102 				iRestartMCUCount--;
       
  3103 				}
       
  3104 
       
  3105 			iCurrentMCUHorzCount = 0;
       
  3106 			}
       
  3107 		iCurrentMCUVertCount = 0;
       
  3108 		}
       
  3109 
       
  3110 	for (TInt count = 0; count < iFrameInfo.iNumberOfComponents; count++)
       
  3111 		iMCUBufferPtr[count] = iMCUBuffer[count];
       
  3112 
       
  3113 	ResetState();
       
  3114 	iProcessing = EFalse;
       
  3115 	}
       
  3116 
       
  3117 void CProgressiveJpgReadCodec::InitDrawFrame()
       
  3118 	{
       
  3119 	iCurrentDrawMCU = 0;
       
  3120 	TInt numberOfComponents = iMonochrome ? 1 : iFrameInfo.iNumberOfComponents;
       
  3121 	for (TInt count = 0; count < numberOfComponents; count++)
       
  3122 		{
       
  3123 		iDrawMCUPtr[count] = iMCUBuffer[count];
       
  3124 		}
       
  3125 
       
  3126 	if (!iImageFrameCodecPtr)
       
  3127 		{
       
  3128 		CImageProcessor* const imageProc = ImageProcessor();
       
  3129 		imageProc->SetPos(TPoint(0,0));
       
  3130 		}
       
  3131 	}
       
  3132 
       
  3133 TBool CProgressiveJpgReadCodec::DrawFrameL()
       
  3134 	{
       
  3135 	TInt numberOfComponents = iMonochrome ? 1 : iFrameInfo.iNumberOfComponents;
       
  3136 
       
  3137 	TDataUnit dataUnit;
       
  3138 	CImageProcessor* const imageProc = ImageProcessor();
       
  3139 
       
  3140 	const TInt drawMCULimit = Min(iCurrentDrawMCU + KMaxMCUPerDraw, iTotalMCUCount);
       
  3141 
       
  3142 	while (iCurrentDrawMCU < drawMCULimit)
       
  3143 		{
       
  3144 		for (TInt compIndex = 0; compIndex < numberOfComponents; compIndex++)
       
  3145 			{
       
  3146 			TQTable& qTable = iQTable[iFrameInfo.iComponent[compIndex].iQTable];
       
  3147 			TDataUnit* compPtr = iComponent[compIndex];
       
  3148 			for (TInt dataUnitCount = iMCUDataUnitCount[compIndex]; dataUnitCount > 0; dataUnitCount--)
       
  3149 				{
       
  3150 				qTable.DeQuantize(dataUnit, *iDrawMCUPtr[compIndex], KJpgDCTBlockSize);
       
  3151 				iCompConf[compIndex].iDCT->InverseTransform(*compPtr, dataUnit);
       
  3152 				iDrawMCUPtr[compIndex]++;
       
  3153 				compPtr++;
       
  3154 				}
       
  3155 			}
       
  3156 
       
  3157 		if (imageProc)
       
  3158 			{
       
  3159 			WriteMCU();
       
  3160 			imageProc->SetPixelBlock(iRgbBuffer);
       
  3161 			}
       
  3162 		else
       
  3163 			{
       
  3164 			RArray<const TDataUnit*> dataUnits;
       
  3165 			CleanupClosePushL(dataUnits);
       
  3166 			for (TInt compIndex = 0; compIndex < iFrameInfo.iNumberOfComponents; compIndex++)
       
  3167 				{
       
  3168 				TDataUnit* compPtr = iComponent[compIndex];
       
  3169 				TInt numSamples = iMCUDataUnitCount[compIndex];
       
  3170 				while (numSamples > 0)
       
  3171 					{
       
  3172 					numSamples--;
       
  3173 					User::LeaveIfError(dataUnits.Append(compPtr++));
       
  3174 					}
       
  3175 				}
       
  3176 			iImageFrameCodecPtr->ProcessL(dataUnits);
       
  3177 			CleanupStack::PopAndDestroy(1, &dataUnits);
       
  3178 			}
       
  3179 
       
  3180 		iCurrentDrawMCU++;
       
  3181 		}
       
  3182 
       
  3183 	if (iCurrentDrawMCU < iTotalMCUCount)
       
  3184 		{
       
  3185 		return EFalse;
       
  3186 		}
       
  3187 
       
  3188 	return ETrue;
       
  3189 	}
       
  3190 
       
  3191 void CProgressiveJpgReadCodec::GetDCValueL(TDataUnit& aDataUnit,const TDecHuffmanTable& aHuffmanTable,TInt& aDCPredictor)
       
  3192 	{
       
  3193 	TInt size = GetHuffmanCodeL(aHuffmanTable);
       
  3194 	TInt amplitude = (size > 0) ? GetBinaryNumberL(size) : 0;
       
  3195 	aDCPredictor += amplitude;
       
  3196 	ASSERT(aDCPredictor <= KMaxTInt16 && aDCPredictor >= KMinTInt16);
       
  3197 	aDataUnit.iCoeff[0] = TInt16(aDCPredictor << iScanInfo.iSuccessiveApproximationBitsLow);
       
  3198 	}
       
  3199 
       
  3200 TInt CProgressiveJpgReadCodec::GetACValuesL(TDataUnit& aDataUnit,const TDecHuffmanTable& aHuffmanTable)
       
  3201 	{
       
  3202 	TInt16* valuePtr = &aDataUnit.iCoeff[iScanInfo.iStartSpectralSelection];
       
  3203 	TInt16* valuePtrLimit = &aDataUnit.iCoeff[iScanInfo.iEndSpectralSelection + 1];
       
  3204 
       
  3205 	while (valuePtr < valuePtrLimit)
       
  3206 		{
       
  3207 		TInt s = GetHuffmanCodeL(aHuffmanTable);
       
  3208 		const TInt r = s >> 4;
       
  3209 		s &= 0x0f;
       
  3210 		if (s > 0)
       
  3211 			{
       
  3212 			valuePtr += r;
       
  3213 
       
  3214 			if (valuePtr < valuePtrLimit)
       
  3215 				*valuePtr++ |= TInt16(GetBinaryNumberL(s) << iScanInfo.iSuccessiveApproximationBitsLow);
       
  3216 			}
       
  3217 		else
       
  3218 			{
       
  3219 			if (r == 15) // Zero run length
       
  3220 				valuePtr += 16;
       
  3221 			else
       
  3222 				{
       
  3223 				TInt eobRun = 1 << r;
       
  3224 				if (r > 0)
       
  3225 					eobRun += GetPositiveBinaryNumberL(r);
       
  3226 				return eobRun - 1;
       
  3227 				}
       
  3228 			}
       
  3229 		}
       
  3230 	return 0;
       
  3231 	}
       
  3232 
       
  3233 void CProgressiveJpgReadCodec::RefineACValuesL(TDataUnit& aDataUnit,const TDecHuffmanTable& aHuffmanTable)
       
  3234 	{
       
  3235 	TInt s = 0;
       
  3236 	TInt r;
       
  3237 	TInt16* valuePtr = &aDataUnit.iCoeff[iScanInfo.iStartSpectralSelection];
       
  3238 	TInt16* valuePtrLimit = &aDataUnit.iCoeff[iScanInfo.iEndSpectralSelection];
       
  3239 
       
  3240 	TInt err;
       
  3241 	TInt numNewNonZero = 0;
       
  3242 	TInt16* newNonZeroPosition[KJpgDCTBlockSize];
       
  3243 	TInt oldEobRun = iEobRun;
       
  3244 	if (iEobRun == 0)
       
  3245 		{
       
  3246 		for (; valuePtr <= valuePtrLimit; valuePtr++)
       
  3247 			{
       
  3248 			TRAP(err,s = GetHuffmanCodeL(aHuffmanTable));
       
  3249 			if (err == KErrCompletion)
       
  3250 				goto OutOfData;
       
  3251 			User::LeaveIfError(err);
       
  3252 			r = s >> 4;
       
  3253 			s &= 0x0f;
       
  3254 			if (s > 0)
       
  3255 				{
       
  3256 				TBool nextBit = EFalse;
       
  3257 				TRAP(err,nextBit = NextBitL());
       
  3258 				if (err == KErrCompletion)
       
  3259 					goto OutOfData;
       
  3260 				User::LeaveIfError(err);
       
  3261 				if (nextBit)
       
  3262 					s = iP1;
       
  3263 				else
       
  3264 					s = iM1;
       
  3265 				}
       
  3266 			else
       
  3267 				{
       
  3268 				if (r != 15)
       
  3269 					{
       
  3270 					iEobRun = 1 << r;
       
  3271 					if (r > 0)
       
  3272 						{
       
  3273 						TRAP(err,iEobRun += GetPositiveBinaryNumberL(r));
       
  3274 						if (err == KErrCompletion)
       
  3275 							goto OutOfData;
       
  3276 						User::LeaveIfError(err);
       
  3277 						}
       
  3278 					break;
       
  3279 					}
       
  3280 				}
       
  3281 
       
  3282 			do
       
  3283 				{
       
  3284 				TInt16* coef = valuePtr;
       
  3285 				if (*coef != 0)
       
  3286 					{
       
  3287 					TBool nextBit = EFalse;
       
  3288 					TRAP(err,nextBit = NextBitL());
       
  3289 					if (err == KErrCompletion)
       
  3290 						goto OutOfData;
       
  3291 					User::LeaveIfError(err);
       
  3292 					if (nextBit)
       
  3293 						{
       
  3294 						if ((*coef & iP1) == 0)
       
  3295 							{
       
  3296 							if (*coef >= 0)
       
  3297 								*coef = TInt16(*coef + iP1);
       
  3298 							else
       
  3299 								*coef = TInt16(*coef + iM1);
       
  3300 							}
       
  3301 						}
       
  3302 					}
       
  3303 				else
       
  3304 					{
       
  3305 					if (--r < 0)
       
  3306 						break;
       
  3307 					}
       
  3308 				valuePtr++;
       
  3309 				}
       
  3310 			while (valuePtr <= valuePtrLimit);
       
  3311 
       
  3312 			if (s != 0)
       
  3313 				{
       
  3314 				*valuePtr = TInt16(s);
       
  3315 				newNonZeroPosition[numNewNonZero++] = valuePtr;
       
  3316 				}
       
  3317 			}
       
  3318 		}
       
  3319 
       
  3320 	if (iEobRun > 0)
       
  3321 		{
       
  3322 		for (; valuePtr <= valuePtrLimit; valuePtr++)
       
  3323 			{
       
  3324 			TInt16* coef = valuePtr;
       
  3325 			if (*coef != 0)
       
  3326 				{
       
  3327 				TBool nextBit = EFalse;
       
  3328 				TRAP(err,nextBit = NextBitL());
       
  3329 				if (err == KErrCompletion)
       
  3330 					goto OutOfData;
       
  3331 				User::LeaveIfError(err);
       
  3332 				if (nextBit)
       
  3333 					{
       
  3334 					if ((*coef & iP1) == 0)
       
  3335 						{
       
  3336 						if (*coef >= 0)
       
  3337 							*coef = TInt16(*coef + iP1);
       
  3338 						else
       
  3339 							*coef = TInt16(*coef + iM1);
       
  3340 						}
       
  3341 					}
       
  3342 				}
       
  3343 			}
       
  3344 		iEobRun--;
       
  3345 		}
       
  3346 	return;
       
  3347 
       
  3348 OutOfData:
       
  3349 	while (numNewNonZero > 0)
       
  3350 		*(newNonZeroPosition[--numNewNonZero]) = 0;
       
  3351 	iEobRun = oldEobRun;
       
  3352 
       
  3353 	User::Leave(KErrCompletion);
       
  3354 	}
       
  3355 
       
  3356 #if defined(__ARMCC__)
       
  3357 #pragma push
       
  3358 #pragma thumb 
       
  3359 #endif
       
  3360 	
       
  3361 void CProgressiveJpgReadCodec::LoadHuffmanTableL()
       
  3362 	{
       
  3363 	if (iDataPtr + 4 > iDataPtrLimit)
       
  3364 	    {
       
  3365 	    User::Leave(KErrCompletion);
       
  3366 	    }
       
  3367 		
       
  3368 	TInt length = (iDataPtr[2] << 8) | iDataPtr[3];
       
  3369 
       
  3370 	const TUint8* dataPtrLimit = iDataPtr + length + 2;
       
  3371 	if (dataPtrLimit > iDataPtrLimit)
       
  3372 		User::Leave(KErrCompletion);
       
  3373 
       
  3374 	iDataPtr += 4;
       
  3375 	while (iDataPtr < dataPtrLimit)
       
  3376 		{
       
  3377 		TInt index = *iDataPtr++;
       
  3378 		TBool dcTable = !(index & 0x10);
       
  3379 		index &= 0x0f;
       
  3380 		if (index >= KJpgMaxNumberOfTables)
       
  3381 			User::Leave(KErrCorrupt);
       
  3382 		TDecHuffmanTable& table = dcTable ? iDCHuffmanTable[index] : iACHuffmanTable[index];
       
  3383 		iDataPtr += table.SetL(iDataPtr,dataPtrLimit);
       
  3384 		}
       
  3385 	}
       
  3386 
       
  3387 void CProgressiveJpgReadCodec::LoadSOSL()
       
  3388 	{
       
  3389 	if (iDataPtr + 4 > iDataPtrLimit)
       
  3390 		User::Leave(KErrCompletion);
       
  3391 	TInt length = (iDataPtr[2] << 8) | iDataPtr[3];
       
  3392 
       
  3393 	if (iDataPtr + length + 2 > iDataPtrLimit)
       
  3394 		User::Leave(KErrCompletion);
       
  3395 
       
  3396 	iDataPtr += 4;
       
  3397 	iScanInfo.iNumberOfComponents = *iDataPtr++;
       
  3398 
       
  3399 	// We ony support up to 3 components, even though spec supports up to 4.
       
  3400 	// Additionaly, number must not be greater than in original frame SOS header
       
  3401 	if (iScanInfo.iNumberOfComponents < KJpgMinNumberOfComponents ||
       
  3402 		iScanInfo.iNumberOfComponents > iOriginalFrameInfo.iNumberOfComponents)
       
  3403 		User::Leave(KErrCorrupt);
       
  3404 
       
  3405 	for (TInt count = 0; count < iScanInfo.iNumberOfComponents; count++)
       
  3406 		{
       
  3407 		iScanInfo.iComponent[count].iId = *iDataPtr++;
       
  3408 
       
  3409 		TUint8 table = *iDataPtr++;
       
  3410 		TUint8 DCTable = static_cast<TUint8>(table >> 4);
       
  3411 		TUint8 ACTable = static_cast<TUint8>(table & 0x0f);
       
  3412 
       
  3413 		if(DCTable >= KJpgMaxNumberOfTables || ACTable >= KJpgMaxNumberOfTables)
       
  3414 			User::Leave(KErrCorrupt);
       
  3415 
       
  3416 		iScanInfo.iComponent[count].iDCCodingTable = DCTable;
       
  3417 		iScanInfo.iComponent[count].iACCodingTable = ACTable;
       
  3418 
       
  3419 		iDCHuffmanTable[DCTable].MakeDerivedTableL();
       
  3420 		iACHuffmanTable[ACTable].MakeDerivedTableL();
       
  3421 		}
       
  3422 
       
  3423 	iScanInfo.iStartSpectralSelection = *iDataPtr++;
       
  3424 	iScanInfo.iEndSpectralSelection = *iDataPtr++;
       
  3425 	TUint8 successiveApproximation = *iDataPtr++;
       
  3426 	iScanInfo.iSuccessiveApproximationBitsHigh = successiveApproximation >> 4;
       
  3427 	iScanInfo.iSuccessiveApproximationBitsLow = successiveApproximation & 0x0f;
       
  3428 	iP1 = 1 << iScanInfo.iSuccessiveApproximationBitsLow;
       
  3429 	iM1 = (-1) << iScanInfo.iSuccessiveApproximationBitsLow;
       
  3430 
       
  3431 	iRefinedDCValue = TInt16(1 << iScanInfo.iSuccessiveApproximationBitsLow);
       
  3432 
       
  3433 	// if iRestartInterval is 0, iRestartMCUCount is set to a negative value (KErrNotFound) to skip the 0 trigger points that would call RestartStateL
       
  3434 	// This is done to solve the problem that on some images the iRestartInterval marker is 0 on every frame
       
  3435 	iRestartMCUCount = iFrameInfo.iRestartInterval > 0 ? iFrameInfo.iRestartInterval : KErrNotFound;
       
  3436 	}
       
  3437 
       
  3438 void CProgressiveJpgReadCodec::LoadRestartIntervalL()
       
  3439 	{
       
  3440 	if (iDataPtr + 6 > iDataPtrLimit)
       
  3441 		{
       
  3442 		User::Leave(KErrCompletion);
       
  3443 		}
       
  3444 
       
  3445 	iFrameInfo.iRestartInterval = iDataPtr[5] | (iDataPtr[4] << 8);
       
  3446 	iDataPtr += 6;
       
  3447 
       
  3448 	// if iRestartInterval is 0, iRestartMCUCount is set to a negative value (KErrNotFound) to skip the 0 trigger points that would call RestartStateL
       
  3449 	// This is done to solve the problem that on some images the iRestartInterval marker is 0 on every frame
       
  3450 	iRestartMCUCount = iFrameInfo.iRestartInterval > 0 ? iFrameInfo.iRestartInterval : KErrNotFound;
       
  3451 	}
       
  3452 
       
  3453 // 03/12/03 - function added as a result of INC037134
       
  3454 // needed a way to cleanup buffers when decoding complete
       
  3455 void CProgressiveJpgReadCodec::CleanupBuffers()
       
  3456 	{
       
  3457 	if(!iMCUChunkAllocated)
       
  3458 		{
       
  3459         delete iMCUMemoryBuffer;
       
  3460         iMCUMemoryBuffer = NULL;
       
  3461 		}
       
  3462 	else
       
  3463 		{
       
  3464 		iMCUChunk.Close();
       
  3465 		}
       
  3466     for (TInt count = 0; count < KJpgNumberOfComponents; count++)
       
  3467 		{
       
  3468 		iMCUBuffer[count] = NULL;
       
  3469 		}
       
  3470 	iMCUChunkAllocated = EFalse;
       
  3471 	}
       
  3472 
       
  3473 // CJpgImageFrameReadCodec
       
  3474 CJpgImageFrameReadCodec::CJpgImageFrameReadCodec(CImageFrame* aFrame)
       
  3475 	{
       
  3476 	iDestination = aFrame;
       
  3477 	}
       
  3478 
       
  3479 CJpgImageFrameReadCodec::~CJpgImageFrameReadCodec()
       
  3480 	{
       
  3481 	delete iImageFrameProcessorPtr;
       
  3482 	}
       
  3483 
       
  3484 CJpgImageFrameReadCodec* CJpgImageFrameReadCodec::NewL(CImageFrame* aFrame)
       
  3485 	{
       
  3486 	CJpgImageFrameReadCodec* self = new(ELeave) CJpgImageFrameReadCodec(aFrame);
       
  3487 	return self;
       
  3488 	}
       
  3489 
       
  3490 void CJpgImageFrameReadCodec::CreateImageProcessorL(const TJpgFrameInfo& aFrameInfo)
       
  3491 	{
       
  3492 	ASSERT(iImageFrameProcessorPtr==NULL);
       
  3493 
       
  3494 	iDestination->SetFrameSizeInPixels(aFrameInfo.iSizeInPixels);
       
  3495 	CJpgImageFrameProcessorUtility::PrepareImageFrameL(aFrameInfo,*iDestination);
       
  3496 	iImageFrameProcessorPtr = CJpgImageFrameProcessorUtility::NewL(*iDestination);
       
  3497 	}
       
  3498 
       
  3499 void CJpgImageFrameReadCodec::ProcessL(const RArray<const TDataUnit*>& aDataUnits)
       
  3500 	{
       
  3501 	iImageFrameProcessorPtr->WriteBlockL(aDataUnits);
       
  3502 	}
       
  3503 
       
  3504 CImageFrame* CJpgImageFrameReadCodec::Destination()
       
  3505 	{
       
  3506 	return iDestination;
       
  3507 	}
       
  3508 
       
  3509 void CJpgImageFrameReadCodec::SetImageFrameBlocksL(CImageFrame* aFrame, const TJpgFrameInfo& aFrameInfo)
       
  3510 	{
       
  3511 	iDestination = aFrame;
       
  3512 
       
  3513 	if(iImageFrameProcessorPtr)
       
  3514 		{
       
  3515 		delete iImageFrameProcessorPtr;
       
  3516 		iImageFrameProcessorPtr = NULL;
       
  3517 		}
       
  3518 
       
  3519 	CJpgImageFrameProcessorUtility::PrepareImageFrameL(aFrameInfo, *iDestination);
       
  3520 	iImageFrameProcessorPtr = CJpgImageFrameProcessorUtility::NewL(*iDestination);
       
  3521 	}
       
  3522 
       
  3523 //
       
  3524 // Multiscan sequential read codec.
       
  3525 //
       
  3526 CMultiScanSequentialJpgReadCodec* CMultiScanSequentialJpgReadCodec::NewL(
       
  3527 	const TJpgFrameInfo& aFrameInfo,
       
  3528 	const TJpgScanInfo& aScanInfo,
       
  3529 	TDecHuffmanTable aDCHuffmanTable[KJpgMaxNumberOfTables],
       
  3530 	TDecHuffmanTable aACHuffmanTable[KJpgMaxNumberOfTables],
       
  3531 	const TQTable aQTable[KJpgMaxNumberOfTables])
       
  3532 	{
       
  3533 	CMultiScanSequentialJpgReadCodec* self = new(ELeave) CMultiScanSequentialJpgReadCodec(
       
  3534 			aFrameInfo,
       
  3535 			aScanInfo,
       
  3536 			aDCHuffmanTable,
       
  3537 			aACHuffmanTable,
       
  3538 			aQTable);
       
  3539 	CleanupStack::PushL(self);
       
  3540 	self->ConstructL(EFalse);	// No cache needed
       
  3541 	CleanupStack::Pop(self);
       
  3542 	return self;
       
  3543 	}
       
  3544 
       
  3545 
       
  3546 //
       
  3547 //
       
  3548 //
       
  3549 CMultiScanSequentialJpgReadCodec::CMultiScanSequentialJpgReadCodec(
       
  3550 		const TJpgFrameInfo& aFrameInfo,
       
  3551 		const TJpgScanInfo& aScanInfo,
       
  3552 		TDecHuffmanTable aDCHuffmanTable[KJpgMaxNumberOfTables],
       
  3553 		TDecHuffmanTable aACHuffmanTable[KJpgMaxNumberOfTables],
       
  3554 		const TQTable aQTable[KJpgMaxNumberOfTables])
       
  3555  :	CSequentialJpgReadCodec(aFrameInfo,
       
  3556 		 aScanInfo,
       
  3557 		 aDCHuffmanTable,
       
  3558 		 aACHuffmanTable,
       
  3559 		 aQTable)
       
  3560 	{
       
  3561 	Mem::Copy(&iFirstScan, &iScanInfo, sizeof(TJpgScanInfo));
       
  3562 	}
       
  3563 
       
  3564 
       
  3565 //
       
  3566 //
       
  3567 //
       
  3568 CMultiScanSequentialJpgReadCodec::~CMultiScanSequentialJpgReadCodec()
       
  3569 	{
       
  3570 	iMCUChunk.Close();
       
  3571 	}
       
  3572 
       
  3573 
       
  3574 //
       
  3575 //
       
  3576 //
       
  3577 void CMultiScanSequentialJpgReadCodec::PreInitFrameL()
       
  3578 	{
       
  3579 	CSequentialJpgReadCodec::PreInitFrameL();
       
  3580 	
       
  3581 	// Restore the first scan.
       
  3582 	Mem::Copy(&iScanInfo, &iFirstScan, sizeof(TJpgScanInfo));
       
  3583 
       
  3584 	for (TInt i = 0; i < KJpgNumberOfComponents; i++)
       
  3585 		{
       
  3586 		iCompAvailable[i] = EFalse;
       
  3587 		}
       
  3588 	
       
  3589 	iMCUChunk.Close();
       
  3590 	iMCUMemoryOffset = NULL;
       
  3591 	}
       
  3592 
       
  3593 
       
  3594 //
       
  3595 //
       
  3596 //
       
  3597 void CMultiScanSequentialJpgReadCodec::InitFrameL(TFrameInfo& aFrameInfo, CFrameImageData& aFrameImageData, TBool aDisableErrorDiffusion, CFbsBitmap& aFrame, CFbsBitmap* aFrameMask)
       
  3598 	{
       
  3599 	CJpgReadCodec::InitFrameL(aFrameInfo, aFrameImageData, aDisableErrorDiffusion, aFrame, aFrameMask);
       
  3600 	
       
  3601 	iTotalMCUBlocks = GetHorzMCUCount() * GetVertMCUCount();
       
  3602 	
       
  3603 	// Prepare RChunk memory for all components
       
  3604 	TInt mcuMemory = 0;
       
  3605 	for (TInt i = 0; i < iFrameInfo.iNumberOfComponents; i++)
       
  3606 		{
       
  3607 		mcuMemory += iTotalMCUBlocks * iMCUDataUnitCount[i] * sizeof(TDataUnit);
       
  3608 		}
       
  3609 	
       
  3610 	TInt err = iMCUChunk.CreateLocal(mcuMemory, mcuMemory);
       
  3611 	JPEG_LEAVE_IF_ERROR(err, "Chunk creation");
       
  3612 	
       
  3613 	iMCUMemoryOffset = iMCUChunk.Base();
       
  3614 	
       
  3615 	// Allocate memory for individual components in scan.
       
  3616 	for (TInt scanInfoIndex = 0; scanInfoIndex < iScanInfo.iNumberOfComponents; scanInfoIndex++)
       
  3617 		{
       
  3618 		TJpgScanInfo::TScanComponentInfo& scanInfo = iScanInfo.iComponent[scanInfoIndex];
       
  3619 		TInt compIndex = ComponentIndexL(scanInfo.iId);
       
  3620 		TInt unitCount = iTotalMCUBlocks * iMCUDataUnitCount[compIndex];
       
  3621 		
       
  3622 		iCompBuf[compIndex] = reinterpret_cast<TDataUnit*>(iMCUMemoryOffset);
       
  3623 		iCompAvailable[compIndex] = ETrue;
       
  3624 		
       
  3625 		iMCUMemoryOffset += unitCount * sizeof(TDataUnit);
       
  3626 		}
       
  3627 	
       
  3628 	iCurrentMcuIdx = 0;
       
  3629 	}
       
  3630 
       
  3631 #if defined(__ARMCC__)
       
  3632 #pragma pop 
       
  3633 #endif
       
  3634 
       
  3635 //
       
  3636 //
       
  3637 //
       
  3638 TFrameState CMultiScanSequentialJpgReadCodec::DoProcessL()
       
  3639 	{
       
  3640 	while (iDataPtr < iDataPtrLimit)
       
  3641 		{
       
  3642 		StoreState();
       
  3643 		if (iRestartMCUCount == 0)
       
  3644 			{
       
  3645 			RestartStateL();
       
  3646 			}
       
  3647 
       
  3648 		const TUint8* const latestDataPtr = iDataPtr;
       
  3649 		TInt error = KErrNone;
       
  3650 		// we do that "if" in order to bypass exception handling which can
       
  3651 		// affect performance of the decoder
       
  3652 		if (iPreviousDataLeft < KMCUDataLeftThreshhold)
       
  3653 			{
       
  3654 			TRAP(error, ProcessMCUL());
       
  3655 			// leave if it wasn't a partial MCU
       
  3656 			if (error != KErrNone && 	(error != KErrEof || latestDataPtr == iDataPtr ||
       
  3657 											(latestDataPtr + sizeof(TUint16) <= iDataPtrLimit
       
  3658 											  && PtrReadUtil::ReadBigEndianUint16(latestDataPtr)==KJpgEOISignature
       
  3659 											)
       
  3660 										)
       
  3661 				)
       
  3662 				{
       
  3663 				JPEG_LEAVE(error, "From ProcessMCUL_1");
       
  3664 				}
       
  3665 			}
       
  3666 		else
       
  3667 			{
       
  3668 			ProcessMCUL();
       
  3669 			}
       
  3670 
       
  3671 		JPEG_LEAVE_IF_ERROR(error, "From slow ProcessMCUL");
       
  3672 		
       
  3673 		//in case of corrupt image, if MCUs exceed total MCUs then leave
       
  3674 		if (iCurrentMcuIdx >= iTotalMCUBlocks)
       
  3675 			{
       
  3676 			JPEG_LEAVE(KErrEof, "Too many MCUs in image");
       
  3677 			}
       
  3678 		
       
  3679 		for (TInt scanInfoIndex = 0; scanInfoIndex < iScanInfo.iNumberOfComponents; scanInfoIndex++)
       
  3680 			{
       
  3681 			TJpgScanInfo::TScanComponentInfo& scanInfo = iScanInfo.iComponent[scanInfoIndex];
       
  3682 			TInt compIndex = ComponentIndexL(scanInfo.iId);
       
  3683 			CopyMCUs(compIndex);
       
  3684 			}
       
  3685 		
       
  3686 		iCurrentMcuIdx++;
       
  3687 		iRestartMCUCount--;
       
  3688 
       
  3689 		if (iDataPtrLimit - iDataPtr < KMCUDataLeftThreshhold)
       
  3690 			{
       
  3691 			TBool needLeave = (iPreviousDataLeft > iDataPtrLimit - iDataPtr);
       
  3692 			iPreviousDataLeft = iDataPtrLimit - iDataPtr;
       
  3693 			if (needLeave && !iNewTableOrScan)
       
  3694 				{
       
  3695 				StoreState();
       
  3696 				User::Leave(KErrCompletion);
       
  3697 				}
       
  3698 			}
       
  3699 		}
       
  3700 	return EFrameIncomplete;
       
  3701 	}
       
  3702 
       
  3703 
       
  3704 //
       
  3705 // Searches Start of Scan marker(0xffda) or Huffman table marker(0xffc4) and gives the position in aPos.
       
  3706 //
       
  3707 TBool CMultiScanSequentialJpgReadCodec::SearchTableOrSosMarker(TBufPtr8& aSourceData, TInt& aPos, TUint16& aMarker)
       
  3708 	{
       
  3709 	const TUint8* ptr = aSourceData.Ptr();
       
  3710 	const TUint8* limit = ptr + aSourceData.Length() - 1;
       
  3711 	
       
  3712 	aPos = 0;
       
  3713 	while ((ptr + 1) <= limit)
       
  3714 		{
       
  3715 		// Mem::Copy must be used to avoid KERN:EXEC 3 access alignment panics on hardware.
       
  3716 		TUint16 data = 0;
       
  3717 		Mem::Copy(&data, ptr++, sizeof(TUint16));
       
  3718 		
       
  3719 		switch (data)
       
  3720 			{
       
  3721 			case 0xDAFF:	// Big-endian version of KJpgSOSSignature.
       
  3722 				aMarker = KJpgSOSSignature;
       
  3723 				return ETrue;
       
  3724 				
       
  3725 			case 0xC4FF:	// Big-endian version of KJpgDHTSignature.
       
  3726 				aMarker = KJpgDHTSignature;
       
  3727 				return ETrue;
       
  3728 				
       
  3729 			default:
       
  3730 				aPos++;
       
  3731 			}
       
  3732 		}
       
  3733 	
       
  3734 	return EFalse;
       
  3735 	}
       
  3736 
       
  3737 
       
  3738 //
       
  3739 // Processes frame data. Renders only on decoding all MCUs.
       
  3740 //
       
  3741 TFrameState CMultiScanSequentialJpgReadCodec::ProcessFrameL(TBufPtr8& aSrc)
       
  3742 	{
       
  3743 	TUint16 marker = 0;
       
  3744 	TInt markerPos = -1;
       
  3745 	iDataPtr = const_cast<TUint8*>(aSrc.Ptr());
       
  3746 	TInt dataLen = aSrc.Length();
       
  3747 	const TUint8* newMarkerAddr = NULL;
       
  3748 	const TUint8* bufferLimit = iDataPtr + dataLen;
       
  3749 	TBool switched = EFalse;
       
  3750 	
       
  3751 	// Exclude table or next scan.
       
  3752 	iNewTableOrScan = SearchTableOrSosMarker(aSrc, markerPos, marker);
       
  3753 	if (iNewTableOrScan)
       
  3754 		{
       
  3755 		newMarkerAddr = iDataPtr + markerPos;
       
  3756 		iDataPtrLimit = const_cast<TUint8*>(newMarkerAddr);
       
  3757 		}
       
  3758 	else
       
  3759 		{
       
  3760 		// If marker 0xff is in the last byte, exclude it.
       
  3761 		iDataPtrLimit = iDataPtr + dataLen;
       
  3762 		if (*(iDataPtrLimit - 1) == 0xFF)
       
  3763 			{
       
  3764 			iDataPtrLimit--;
       
  3765 			}
       
  3766 		}
       
  3767 	
       
  3768 	iPreviousDataLeft = iDataPtrLimit - iDataPtr;
       
  3769 
       
  3770 	TFrameState frameState = EFrameComplete;
       
  3771 	TRAPD(err, frameState = DoProcessL());
       
  3772 	// If there is new scan or table, switch to it.
       
  3773 	if (iNewTableOrScan)
       
  3774 		{
       
  3775 		if (marker == KJpgDHTSignature)
       
  3776 			{
       
  3777 			switched = ProcessHuffmanTableL(newMarkerAddr, bufferLimit);
       
  3778 			}
       
  3779 		else if (marker == KJpgSOSSignature)
       
  3780 			{
       
  3781 			switched = SwitchScanL(newMarkerAddr, bufferLimit);
       
  3782 			}
       
  3783 		}
       
  3784 	
       
  3785 	if (err != KErrNone)
       
  3786 		{
       
  3787 		if (err == KErrCompletion)
       
  3788 			{
       
  3789 			RestoreState();
       
  3790 			frameState = EFrameIncomplete;
       
  3791 			}
       
  3792 		else if (err == KErrEof)
       
  3793 			{
       
  3794 			frameState = EFrameComplete;
       
  3795 			// Render all MCUs.
       
  3796 			RenderMCUsL();
       
  3797 			}
       
  3798 		else
       
  3799 			{
       
  3800 			JPEG_LEAVE(err, "From DoProcessL");
       
  3801 			}
       
  3802 		}
       
  3803 	
       
  3804 	if (switched)
       
  3805 		{
       
  3806 		iDataPtr = const_cast<TUint8*>(newMarkerAddr);
       
  3807 		if (marker == KJpgSOSSignature)
       
  3808 			{
       
  3809 			ResetOnNewScan();
       
  3810 			}
       
  3811 		}
       
  3812 	
       
  3813 	aSrc.Shift(iDataPtr - aSrc.Ptr()); // Shift out used data.
       
  3814 
       
  3815 	return frameState;
       
  3816 	}
       
  3817 
       
  3818 
       
  3819 //
       
  3820 // Switches to new scan if sufficient header information is available.
       
  3821 //
       
  3822 TBool CMultiScanSequentialJpgReadCodec::SwitchScanL(const TUint8*& aScan, const TUint8* aDataLimit)
       
  3823 	{
       
  3824 	const TInt KSosSizeFieldLength = 2;
       
  3825 	if (aScan + sizeof(KJpgSOSSignature) + KSosSizeFieldLength > aDataLimit)
       
  3826 		{
       
  3827 		return EFalse;
       
  3828 		}
       
  3829 	
       
  3830 	// Check for SOS marker.
       
  3831 	TUint16 value = ReadBigEndianUint16(aScan);
       
  3832 	if (value != KJpgSOSSignature)
       
  3833 		{
       
  3834 		return EFalse;
       
  3835 		}
       
  3836 	
       
  3837 	// Read length and check if entire scan is available.
       
  3838 	value = ReadBigEndianUint16(aScan);
       
  3839 	if (aScan + value - KSosSizeFieldLength > aDataLimit)
       
  3840 		{
       
  3841 		return EFalse;
       
  3842 		}
       
  3843 	
       
  3844 	// Keep track of MCUs available for components.
       
  3845 	for (TInt i = 0; i < iScanInfo.iNumberOfComponents; i++)
       
  3846 		{
       
  3847 		TInt compIndex = ComponentIndexL(iScanInfo.iComponent[i].iId);
       
  3848 		iCompMcuCount[compIndex] = iCurrentMcuIdx;
       
  3849 		}
       
  3850 
       
  3851 	iScanInfo.iNumberOfComponents = *aScan;
       
  3852 	// Component id, table selector bytes.
       
  3853 	const TInt KCompBytes = 2;
       
  3854 	// Scan start, scan end, successive approx bytes.
       
  3855 	const TInt KScanBytes = 3;
       
  3856 	if (aScan + (iScanInfo.iNumberOfComponents * KCompBytes) + KScanBytes > aDataLimit)
       
  3857  		{
       
  3858  		// Header length is wrong. Entire header is not available in the buffer.
       
  3859 		return EFalse;
       
  3860 		}
       
  3861 	
       
  3862 	TJpgScanInfoProcessor::ProcessStartOfScanL(aScan, iFrameInfo, iScanInfo, iDCHuffmanTable, iACHuffmanTable);
       
  3863 	
       
  3864 	// Move to next address after scan.
       
  3865 	aScan++;
       
  3866 	for (TInt i = 0; i < iScanInfo.iNumberOfComponents; i++)
       
  3867 		{
       
  3868 		TJpgScanInfo::TScanComponentInfo& scanInfo = iScanInfo.iComponent[i];
       
  3869 		TInt compIndex = ComponentIndexL(scanInfo.iId);
       
  3870 		if (iCompAvailable[compIndex])
       
  3871 			{
       
  3872 			// If a same component repeats, then the file is corrupt. Stop further decoding.
       
  3873 			JPEG_LEAVE(KErrEof, "Repeated component");
       
  3874 			}
       
  3875 		
       
  3876 		TInt unitCount = iTotalMCUBlocks * iMCUDataUnitCount[compIndex];
       
  3877 		iCompBuf[compIndex] = reinterpret_cast<TDataUnit*>(iMCUMemoryOffset);
       
  3878 		iCompAvailable[compIndex] = ETrue;
       
  3879 		
       
  3880 		iMCUMemoryOffset += unitCount * sizeof(TDataUnit);
       
  3881 		}
       
  3882 	
       
  3883 	iCurrentMcuIdx = 0;
       
  3884 	if (iFrameInfo.iRestartInterval > 0)
       
  3885 		{
       
  3886 		iRestartMCUCount = iFrameInfo.iRestartInterval;
       
  3887 		}
       
  3888 	else
       
  3889 		{
       
  3890 		iRestartMCUCount = KErrNotFound;
       
  3891 		}
       
  3892 	
       
  3893 	ResetState();
       
  3894 	return ETrue;
       
  3895 	}
       
  3896 
       
  3897 
       
  3898 //
       
  3899 //
       
  3900 //
       
  3901 TBool CMultiScanSequentialJpgReadCodec::ProcessHuffmanTableL(const TUint8*& aData, const TUint8* aBufferLimit)
       
  3902 	{
       
  3903 	// Length of size field for table marker.
       
  3904 	const TInt KTableMarkerSizeField = 2;
       
  3905 	if (aData + sizeof(KJpgDHTSignature) + KTableMarkerSizeField > aBufferLimit)
       
  3906 		{
       
  3907 		return EFalse;
       
  3908 		}
       
  3909 	
       
  3910 	// Read marker.
       
  3911 	TUint16 value = ReadBigEndianUint16(aData);
       
  3912 	if (value != KJpgDHTSignature)
       
  3913 		{
       
  3914 		return EFalse;
       
  3915 		}
       
  3916 	
       
  3917 	// Read length.
       
  3918 	value = ReadBigEndianUint16(aData);
       
  3919 	
       
  3920 	// Check if entire table data is available in buffer.
       
  3921 	const TUint8* dataLimit = aData + value - KTableMarkerSizeField;
       
  3922 	if (dataLimit > aBufferLimit)
       
  3923 		{
       
  3924 		return EFalse;
       
  3925 		}
       
  3926 	
       
  3927 	THuffmanTableProcessor::ProcessHuffmanTableL(aData, dataLimit, iDCHuffmanTable, iACHuffmanTable);
       
  3928 	
       
  3929 	return ETrue;
       
  3930 	}
       
  3931 
       
  3932 
       
  3933 //
       
  3934 // Copies MCUs to component buffers, where they are accumulated.
       
  3935 //
       
  3936 void CMultiScanSequentialJpgReadCodec::CopyMCUs(TInt aCompIdx)
       
  3937 	{
       
  3938 	if (iMonochrome && (aCompIdx != KYComp))
       
  3939 		{
       
  3940 		return;
       
  3941 		}
       
  3942 	
       
  3943 	// Assumes that iCurrentMcuIdx value start from 0.
       
  3944 	const TDataUnit* src = iComponent[aCompIdx];
       
  3945 	TDataUnit* des = iCompBuf[aCompIdx];
       
  3946 	
       
  3947 	// If Y with 4 DUs.
       
  3948 	if ((aCompIdx == KYComp) && (iMCUDataUnitCount[KYComp] == 4))
       
  3949 		{
       
  3950 		// Rearranges Y Data Units, so that they are rendered sequentially.
       
  3951 	   	TInt mcusPerLine = GetHorzMCUCount();
       
  3952 		TInt dusPerLine = mcusPerLine * iMCUDataUnitCount[KYComp];
       
  3953 		TInt line =  iCurrentMcuIdx / mcusPerLine;
       
  3954 		TDataUnit* lineAddr = des + (line * dusPerLine);
       
  3955 		TInt mcuIdxInLine = iCurrentMcuIdx - (line * mcusPerLine);
       
  3956 		
       
  3957 		// Copy offset.
       
  3958 		TInt offset = 0;
       
  3959 		if ((mcuIdxInLine + 1) <= mcusPerLine / 2)
       
  3960 			{
       
  3961 			offset = mcuIdxInLine * 8;
       
  3962 			}
       
  3963 		else
       
  3964 			{
       
  3965 			TInt idx = (mcuIdxInLine + 1) - (mcusPerLine / 2);
       
  3966 			offset = (idx  - 1) * 8 + 2;
       
  3967 			}
       
  3968 		
       
  3969 		// Copy 2 DUs at a time, giving 2 DU space.
       
  3970 		Mem::Copy(lineAddr + offset, src, 2 * sizeof(TDataUnit));
       
  3971 		Mem::Copy(lineAddr + offset + 4, src + 2, 2 * sizeof(TDataUnit));
       
  3972 		}
       
  3973 	else
       
  3974 		{
       
  3975 		des += iCurrentMcuIdx * iMCUDataUnitCount[aCompIdx];
       
  3976 		Mem::Copy(des, src, iMCUDataUnitCount[aCompIdx] * sizeof(TDataUnit));
       
  3977 		}
       
  3978 	}
       
  3979 
       
  3980 
       
  3981 //
       
  3982 // Sets up iComponent to point to the right parts of the RChunk memory.
       
  3983 //
       
  3984 void CMultiScanSequentialJpgReadCodec::PrepareToRenderMCU(TInt aMCUIndex)
       
  3985 	{
       
  3986 	JPEG_ASSERT(aMCUIndex >= 0);
       
  3987 	
       
  3988 	for (TInt i = 0; i < KJpgNumberOfComponents; i++)
       
  3989 		{
       
  3990 		if (iCompAvailable[i])
       
  3991 			{
       
  3992 			iComponent[i] = &iCompBuf[i][aMCUIndex * iMCUDataUnitCount[i]];
       
  3993 			}
       
  3994 		}
       
  3995 	}
       
  3996 
       
  3997 
       
  3998 //
       
  3999 // Sends all MCUs of components to rendering.
       
  4000 //
       
  4001 void CMultiScanSequentialJpgReadCodec::RenderMCUsL()
       
  4002 	{
       
  4003 	for (TInt i = 0; i < iScanInfo.iNumberOfComponents; i++)
       
  4004 		{
       
  4005 		// Keep track of number of MCUs available for components.
       
  4006 		TInt compIndex = ComponentIndexL(iScanInfo.iComponent[i].iId);
       
  4007 		iCompMcuCount[compIndex] = iCurrentMcuIdx;
       
  4008 		}
       
  4009 	
       
  4010 	FillEmptyMCUs();
       
  4011 	
       
  4012 	while (iNeededMCU != KErrCompletion)
       
  4013 		{
       
  4014 		iStreamMCU = iNeededMCU;	// Maintain behaviour of CSequentialJpgReadCodec.
       
  4015 
       
  4016 		Mem::Copy(&iComponentCpy, &iComponent, sizeof(TDataUnit*) * KJpgNumberOfComponents);
       
  4017 		PrepareToRenderMCU(iNeededMCU);
       
  4018 		PostProcessMCUL(EFalse);
       
  4019 		Mem::Copy(&iComponent, &iComponentCpy, sizeof(TDataUnit*) * KJpgNumberOfComponents);
       
  4020 
       
  4021 		
       
  4022 		iNeededMCU = iMCUStore->GetNextMCU();
       
  4023 		}
       
  4024 	}
       
  4025 
       
  4026 
       
  4027 //
       
  4028 // If the number of available MCUs for Cb and Cr is less than that of Y, those MCUs are filled with 0x7f.
       
  4029 //
       
  4030 void CMultiScanSequentialJpgReadCodec::FillEmptyMCUs()
       
  4031 	{
       
  4032 	// MCU index to start filling. This may involve overwriting existing U or V data.
       
  4033 	TInt startIdx = Min(iCompMcuCount[KUComp], iCompMcuCount[KVComp]);
       
  4034 	for (TInt i = KUComp; i <= KVComp; i++)
       
  4035 		{
       
  4036 		if (iComponent[i] == NULL)
       
  4037 			{
       
  4038 			// If monochrome or if the component is not part of image.
       
  4039 			continue;
       
  4040 			}
       
  4041 		
       
  4042 		TDataUnit* des = NULL;
       
  4043 		if (iCompAvailable[i])
       
  4044 			{
       
  4045 			des = iCompBuf[i];
       
  4046 			des += startIdx * iMCUDataUnitCount[i];
       
  4047 			TInt dus = (iCompMcuCount[KYComp] - startIdx) * iMCUDataUnitCount[i];
       
  4048 			for (TInt k = 0; k < dus; k++)
       
  4049 				{
       
  4050 				FillEmptyDU(&des[k]);
       
  4051 				}
       
  4052 			}
       
  4053 		else
       
  4054 			{
       
  4055 			des = iComponent[i];
       
  4056 			// If component is not at all available, fill iComponent[] buffer with 0x7f.
       
  4057 			for (TInt k = 0; k < iMCUDataUnitCount[i]; k++)
       
  4058 				{
       
  4059 				FillEmptyDU(&des[k]);
       
  4060 				}
       
  4061 			}
       
  4062 		}
       
  4063 	}
       
  4064 
       
  4065 
       
  4066 //
       
  4067 // Resets the data members so that new scan can be started
       
  4068 //
       
  4069 void CMultiScanSequentialJpgReadCodec::ResetOnNewScan()
       
  4070 	{
       
  4071 	iInitialDataPtr = NULL;
       
  4072 	iBitBufferPtrLimit = NULL;
       
  4073 	iDataValue = 0;
       
  4074 	iInitialDataValue = 0;
       
  4075 	iBitsLeft = 0;
       
  4076 	iInitialBitsLeft = 0;
       
  4077 	
       
  4078 	for (TInt i = 0; i < KJpgNumberOfComponents; i++)
       
  4079 		{
       
  4080 		iDCPredictor[i] = 0;
       
  4081 		iInitialDCPredictor[i] = 0;
       
  4082 		}
       
  4083 	}
       
  4084 
       
  4085 
       
  4086 //
       
  4087 // Fills the given Data Unit with 0x7f.
       
  4088 //
       
  4089 void CMultiScanSequentialJpgReadCodec::FillEmptyDU(TDataUnit* pDU)
       
  4090 	{
       
  4091 	JPEG_ASSERT(pDU);
       
  4092 	JPEG_ASSERT(pDU->iCoeff);
       
  4093 	
       
  4094 	TDataUnit::TDataUnitElemType* ptr = pDU->iCoeff;
       
  4095 	for(TInt i = 0; i < KJpgDCTBlockSize; i++)
       
  4096 		{
       
  4097 		*ptr++ = 0x7f;
       
  4098 		}
       
  4099 	}
       
  4100 
       
  4101 
       
  4102