imaging/imagingplugins/codecs/ICOCodec/icomaskprocessor.cpp
changeset 0 5752a19fdefe
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/imaging/imagingplugins/codecs/ICOCodec/icomaskprocessor.cpp	Wed Aug 25 12:29:52 2010 +0300
@@ -0,0 +1,307 @@
+// Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+//
+
+#include <fbs.h>
+#include "icomaskprocessor.h"
+
+const TInt 	KIcoMaskProcessorBufferSize = 1024; // size matches that of the CPixelWriter buffer
+const TUint KRGBMask = 0x00FFFFFF;
+const TInt	KAlphaShift = 24;
+
+CIcoMaskProcessor* CIcoMaskProcessor::NewL(TInt aReductionFactor)
+	{
+	return new (ELeave) CIcoMaskProcessor(aReductionFactor);
+	}
+
+CIcoMaskProcessor::CIcoMaskProcessor(TInt aReductionFactor)
+:iReductionFactor(aReductionFactor)
+	{
+	}
+
+CIcoMaskProcessor::~CIcoMaskProcessor()
+	{
+	Reset();
+	}
+
+void CIcoMaskProcessor::Reset()
+	{
+	iReductionFactor = 0;
+	iImageRegion.SetRect(0,0,0,0);
+	iPosition.SetXY(0,0);
+	iScaledPosition.SetXY(0,0);
+	iYIncrement = 0;
+	iPixelPadding = 0;
+	iPixelsToSkip = 0;
+	delete[] iMaskBuffer;
+	iMaskBuffer = NULL;
+	delete[] iScaledMaskBuffer;
+	iScaledMaskBuffer = NULL;
+	}
+
+void CIcoMaskProcessor::PrepareL(CFbsBitmap& aBitmap,const TRect& aImageRect)
+	{
+	ASSERT(aImageRect.Width() != 0);
+	ASSERT(aImageRect.Height() != 0);
+	ASSERT(iMaskBuffer == NULL);
+	
+	iDestBitmap = &aBitmap;
+	iImageRegion = aImageRect;
+	
+	if(iReductionFactor)
+		{
+		// Create the buffer to hold the unscaled pixels.
+		iMaskBuffer = new (ELeave) TRgb[KIcoMaskProcessorBufferSize >> iReductionFactor];
+		iMaskBufferPtr = iMaskBuffer;
+		iMaskBufferPtrLimit = iMaskBuffer + (KIcoMaskProcessorBufferSize >> iReductionFactor);
+		
+		// Create the buffer to hold the 'merged' pixel values, represented by TMonochromeSum.
+		TInt scaledBufferSize = (iImageRegion.iBr.iX + (1<<iReductionFactor) -1 ) >> iReductionFactor;
+		iScaledMaskBuffer = new (ELeave) TMonochromeSum[scaledBufferSize];
+		iScaledMaskBufferPtrLimit = iScaledMaskBuffer + scaledBufferSize;
+		Mem::FillZ(iScaledMaskBuffer, scaledBufferSize * sizeof(TMonochromeSum));
+		}
+	else
+		{
+		// Create the buffer to hold the unscaled pixels.
+		iMaskBuffer = new (ELeave) TRgb[KIcoMaskProcessorBufferSize];
+		iMaskBufferPtr = iMaskBuffer;
+		iMaskBufferPtrLimit = iMaskBuffer + KIcoMaskProcessorBufferSize;
+		}
+	}
+
+void CIcoMaskProcessor::PrepareL(CFbsBitmap& /*aBitmap*/, const TRect& /*aImageRect*/, const TSize& /*aRgbBlockSize*/)
+	{
+	ASSERT(EFalse);
+	}
+
+// ICO data is stored from bottom-up, so iYIncrement is negative (draw bottom-up).
+void CIcoMaskProcessor::SetYPosIncrement(TInt aYInc)
+	{
+	iYIncrement = aYInc;
+	}
+
+void CIcoMaskProcessor::SetLineRepeat(TInt /*aLineRepeat*/)
+	{
+	ASSERT(EFalse);
+	}
+
+/*
+ICO data contains padding.  Each mask pixel is represented by 1 bit, thus there
+can be up to 31 bits of padding in the decoded data buffer to skip.
+*/
+void CIcoMaskProcessor::SetPixelPadding(TInt aNumberOfPixels)
+	{
+	iPixelPadding = aNumberOfPixels;
+	}
+
+/*
+Function to handle a mask pixel, and thus is either fully opauq white (0xFFFFFFFF) or fully
+transparent black (0x00000000).
+*/
+TBool CIcoMaskProcessor::SetPixel(TRgb aColor)
+	{
+	if(iReductionFactor)
+		{
+		if(iScaledPosition.iX < iImageRegion.Width()) // Ignore decoded padding
+			{
+			// When scaling by half, for example, take every other pixel on the first two lines and
+			// sum their values.  This is then processed later into a single pixel value.
+			TMonochromeSum* sumPtr = iScaledMaskBuffer + (iScaledPosition.iX >> iReductionFactor);
+			sumPtr->iLevel += TColorConvertor::RgbToMonochrome(aColor);
+			sumPtr->iCount++;
+			}
+		
+		iScaledPosition.iX++;
+				
+		if(iScaledPosition.iX == iImageRegion.Width() + iPixelPadding)
+			{
+			TInt newY = iScaledPosition.iY + iYIncrement;
+			TBool outsideOfBuffer = ((newY ^ iScaledPosition.iY) >> iReductionFactor) != 0;
+			
+			iScaledPosition.iY = newY;
+			iScaledPosition.iX = 0;
+			
+			if(outsideOfBuffer)
+				{
+				return FlushPixels();
+				}
+			}
+		}
+	else
+		{
+		*iMaskBufferPtr++ = aColor;
+		if(iMaskBufferPtr == iMaskBufferPtrLimit)
+			{		
+			return FlushPixels();
+			}
+		}
+
+	return EFalse;
+	}
+
+TBool CIcoMaskProcessor::SetPixelRun(TRgb /*aColor*/, TInt /*aCount*/)
+	{
+	ASSERT(EFalse);
+	return EFalse;
+	}
+
+TBool CIcoMaskProcessor::SetPixels(TRgb* /*aColorBuffer*/, TInt /*aBufferLength*/)
+	{
+	ASSERT(EFalse);
+	return EFalse;
+	}
+
+TBool CIcoMaskProcessor::SetPixelBlock(TRgb* /*aColorBuffer*/)
+	{
+	ASSERT(EFalse);
+	return EFalse;
+	}
+
+TBool CIcoMaskProcessor::SetMonoPixel(TInt /*aGray256*/)
+	{
+	ASSERT(EFalse);
+	return EFalse;
+	}
+
+TBool CIcoMaskProcessor::SetMonoPixelRun(TInt /*aGray256*/, TInt /*aCount*/)
+	{
+	ASSERT(EFalse);
+	return EFalse;
+	}
+
+TBool CIcoMaskProcessor::SetMonoPixels(TUint32* /*aGray256Buffer*/, TInt /*aBufferLength*/)
+	{
+	ASSERT(EFalse);
+	return EFalse;
+	}
+
+TBool CIcoMaskProcessor::SetMonoPixelBlock(TUint32* /*aGray256Buffer*/)
+	{
+	ASSERT(EFalse);
+	return EFalse;
+	}
+
+TBool CIcoMaskProcessor::SetPos(const TPoint& aPosition)
+	{
+	iPosition.SetXY(aPosition.iX >> iReductionFactor, aPosition.iY >> iReductionFactor);
+	iScaledPosition = aPosition;
+	return ETrue;
+	}
+/*
+Converts the pixel values in the internally held iScaledMaskBuffer into a single pixel value which is then
+added to the iMaskBuffer.
+*/
+void CIcoMaskProcessor::ProcessScaledPixels()
+	{
+	TMonochromeSum* scaledSumPtr = iScaledMaskBuffer;
+	TMonochromeSum* scaledSumPtrLimit = iScaledMaskBuffer + (iImageRegion.Width() >> iReductionFactor);
+	TRgb* maskBufferPtr = iMaskBuffer;
+	
+	TInt fullCountFactor = 2 * iReductionFactor;
+	TInt fullCount = 1 << fullCountFactor;
+
+	do
+		{		
+		TInt level = scaledSumPtr->iLevel;
+		TInt count = scaledSumPtr->iCount;
+
+		if(count == fullCount)
+			{
+			level >>= fullCountFactor;
+			}
+		else if(count!=0)
+			{
+			level /= count;
+			}
+		else
+			break;
+
+		maskBufferPtr->SetInternal(level);
+		maskBufferPtr++;
+
+		scaledSumPtr++;
+		}
+	while(scaledSumPtr < scaledSumPtrLimit);
+	
+	iMaskBufferPtr = maskBufferPtr;
+	
+	TInt numPixels = scaledSumPtr - iScaledMaskBuffer;
+	Mem::FillZ(iScaledMaskBuffer, numPixels * sizeof(TMonochromeSum));
+	}
+
+TBool CIcoMaskProcessor::FlushPixels()
+	{
+	if(iReductionFactor)
+		{
+		ProcessScaledPixels();
+		}
+	
+	return DoFlushPixels();
+	}
+
+/*
+The pixelvalues (i.e. mask values) in the iMaskBuffer are added to the RGB colour values held in the
+destination bitmap (which have been put there by another image processor), and then put back into the
+destination bitmap.
+*/
+TBool CIcoMaskProcessor::DoFlushPixels()
+	{
+	TRgb* maskBufferPtrLimit = iMaskBufferPtr;
+	iMaskBufferPtr = iMaskBuffer; // reset pointer
+	
+	TBitmapUtil bitmapUtil(iDestBitmap);
+	bitmapUtil.Begin(iPosition);
+	
+	for(TRgb* maskBufferPtr = iMaskBuffer; maskBufferPtr < maskBufferPtrLimit; maskBufferPtr++)
+		{		
+		TInt skip = Min(iPixelsToSkip, maskBufferPtrLimit - maskBufferPtr);
+		maskBufferPtr += skip;
+		iPixelsToSkip -= skip;
+		if(iPixelsToSkip > 0 || maskBufferPtr == maskBufferPtrLimit)
+			{
+			break;
+			}
+				
+		// Set the alpha channel of the bitmap
+		TUint32 pixel = bitmapUtil.GetPixel();
+		pixel &= KRGBMask; // clear alpha channel
+		pixel |= maskBufferPtr->Internal() << KAlphaShift; // set alpha
+
+		bitmapUtil.SetPixel(pixel);
+		iPosition.iX++;
+		
+		if(iPosition.iX >= (iImageRegion.iBr.iX >> iReductionFactor))
+			{
+			iPosition.iX = 0;
+			iPosition.iY += iYIncrement;
+			bitmapUtil.SetPos(iPosition);
+			
+			if(iPosition.iY < 0)
+				{
+				return ETrue;
+				}
+			
+			iPixelsToSkip = (iReductionFactor ? 0 : iPixelPadding);
+			}
+		else
+			{
+			bitmapUtil.IncXPos();
+			}
+		}
+	
+	bitmapUtil.End();
+	
+	return EFalse;
+	}