fbs/fontandbitmapserver/trasterizer/src/examplerasterizer.cpp
changeset 0 5d03bc08d59c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fbs/fontandbitmapserver/trasterizer/src/examplerasterizer.cpp	Tue Feb 02 01:47:50 2010 +0200
@@ -0,0 +1,503 @@
+// 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 "examplerasterizer.h"
+#include <s32mem.h>
+#include <fbs.h>
+
+/** Create a new example rasterizer.
+
+@return A pointer to a newly constructed CFbsRasterizer object if successful,
+or NULL if no memory is available.
+ */
+EXPORT_C CFbsRasterizer* CFbsRasterizer::New()
+	{
+	return new CExampleRasterizer;
+	}
+
+
+/** Constructor.
+ */
+CExampleRasterizer::CExampleRasterizer()
+	: iRegisteredBmps(_FOFF(CRegisteredBitmap, iLink)), iRecentBmps(_FOFF(CRegisteredBitmap, iLink))
+	{}
+
+/** Destructor.
+ */
+CExampleRasterizer::~CExampleRasterizer()
+	{
+	while (!iRegisteredBmps.IsEmpty())
+		{
+		delete iRegisteredBmps.First();
+		}
+	while (!iRecentBmps.IsEmpty())
+		{
+		delete iRecentBmps.First();
+		}
+	delete iIdle;
+	}
+
+/** Register a bitmap with this rasterizer for rendering.
+
+In this example an extended bitmap is a tricolour flag with three coloured stripes of the same size 
+being either vertically or horizontally oriented. The colours to be used in the flag and a TUint8 
+that specifies horizontal or vertical stripes are passed in the aBitmapDesc.iData parameter, which 
+should point to a buffer containing the three stripe colours first, each colour as three TUint8 
+values, followed by a TUint8 value where 1 means horizontal stripes and 0 means vertical stripes.
+
+The only display modes supported by this example rasterizer are EGray256, EColor64K, EColor16MU and EColor16MAP.
+
+If the rasterizer cannot allocate enough memory for rendering the extended bitmap this function 
+will return silently. If an unsupported display mode is passed this function will return silently.
+
+@see CFbsRasterizer::BeginBitmap()
+@see EndBitmap()
+ */
+void CExampleRasterizer::BeginBitmap(TInt64 aBitmapId, const TBitmapDesc& aBitmapDesc, const TRegion* aRegionOfInterest)
+	{
+	// Check that the passed extended bitmap description is valid
+	if ((aBitmapDesc.iSizeInPixels.iWidth <= 0) || (aBitmapDesc.iSizeInPixels.iHeight <= 0)
+		// This test rasterizer only supports EGray256, EColor64K, EColor16MU and EColor16MAP
+		|| ((aBitmapDesc.iDispMode != EGray256) && (aBitmapDesc.iDispMode != EColor64K) && (aBitmapDesc.iDispMode != EColor16MU) && (aBitmapDesc.iDispMode != EColor16MAP))
+		|| (aBitmapDesc.iDataType != KUidExampleExtendedBitmap)
+		|| (aBitmapDesc.iData == NULL)
+		|| (aBitmapDesc.iDataSize <= 0))
+		{
+#ifdef _DEBUG
+		RDebug::Printf("Example Rasterizer Error: Invalid TBitmapDesc passed to CExampleRasterizer::BeginBitmap()");
+#endif // _DEBUG
+		return;
+		}
+	
+	// Check if the bitmap is already registered
+	CRegisteredBitmap* foundRegBmp = RegisteredBitmap(aBitmapId);
+	if (!foundRegBmp)
+		{
+		// Not registered: check if the bitmap is in the cache of recently used bitmaps
+		foundRegBmp = RecentBitmap(aBitmapId);
+		if (foundRegBmp)
+			{
+			// Take the bitmap out of the cache and put it in the list of registered bitmaps
+			foundRegBmp->iLink.Deque();
+			iTotalRecentBmpSize -= foundRegBmp->iBufLength;
+			iRegisteredBmps.AddLast(*foundRegBmp);
+			}
+		}
+	if (foundRegBmp)
+		{
+#ifdef _DEBUG
+		// Make sure an extended bitmap is not registered more than once with different attributes
+		if ((foundRegBmp->iSizeInPixels != aBitmapDesc.iSizeInPixels)
+			|| (foundRegBmp->iDispMode != aBitmapDesc.iDispMode)
+			|| (foundRegBmp->iDataType != aBitmapDesc.iDataType))
+			{
+			RDebug::Printf("Example Rasterizer Error: CExampleRasterizer::BeginBitmap() called for an extended bitmap that has already been registered with a different TBitmapDesc");
+			}
+#endif // _DEBUG
+		
+		// This bitmap is already registered, just increment its reference count and return
+		foundRegBmp->iRefCount++;
+		return;
+		}
+	
+	// Get the scanline length we should use for this display mode as the scanlines we draw must be 32-bit aligned
+	TInt scanLineLength = CFbsBitmap::ScanLineLength(aBitmapDesc.iSizeInPixels.iWidth, aBitmapDesc.iDispMode);
+	// Create a CRegisteredBitmap object to save the pre-rendered bitmap
+	TInt bufLength = scanLineLength * aBitmapDesc.iSizeInPixels.iHeight;
+	// Allocate bufLength extra bytes for the embedded pixel buffer
+	CRegisteredBitmap* regBmp = new(bufLength) CRegisteredBitmap(aBitmapId, aBitmapDesc, bufLength);
+	if (!regBmp)
+		{
+#ifdef _DEBUG
+		RDebug::Printf("Example Rasterizer Error: Failed to allocate memory");
+#endif // _DEBUG		
+		return;
+		}
+	
+	// Pre-render the flag that the extended bitmap represents
+	RMemReadStream readStream;
+	readStream.Open(aBitmapDesc.iData, aBitmapDesc.iDataSize);
+	TInt err = regBmp->Draw(readStream, aRegionOfInterest);
+	readStream.Close();
+	if (err != KErrNone)
+		{
+#ifdef _DEBUG
+		RDebug::Printf("Example Rasterizer Error: CExampleRasterizer::CRegisteredBitmap::Draw() returned %d", err);
+#endif // _DEBUG
+		delete regBmp;
+		return;
+		}
+	
+	// Success
+	iRegisteredBmps.AddLast(*regBmp);
+	regBmp->iRefCount = 1;
+	}
+
+/** Unregister an extended bitmap from this rasterizer. 
+
+@see CFbsRasterizer::EndBitmap()
+@see BeginBitmap()
+ */
+void CExampleRasterizer::EndBitmap(TInt64 aBitmapId)
+	{
+	CRegisteredBitmap* regBmp = RegisteredBitmap(aBitmapId);
+	if (regBmp)
+		{
+		if (--regBmp->iRefCount == 0)
+			{
+			// Put unregistered bitmap in the cache of recently used bitmaps if wholly pre-rendered
+			// and there is an active scheduler to add the idle-time clean-up active object to
+			if (regBmp->iWhole && CActiveScheduler::Current())
+				{
+				if (!iIdle)
+					{
+					iIdle = CIdle::New(CActive::EPriorityIdle);
+					if (!iIdle)
+						{
+						delete regBmp;
+						return;
+						}
+					}
+				regBmp->iLink.Deque();
+				iRecentBmps.AddFirst(*regBmp);
+				iTotalRecentBmpSize += regBmp->iBufLength;
+				// Delete the least recently used bitmaps if the maximum size of the cache is exceeded
+				while (iTotalRecentBmpSize > KMaxRecentBmpCacheSize)
+					{
+					regBmp = iRecentBmps.Last();
+					iTotalRecentBmpSize -= regBmp->iBufLength;
+					delete regBmp;
+					}
+				// If the cache is not empty make sure the idle-time clean-up active object is scheduled to run
+				if (!iRecentBmps.IsEmpty() && !iIdle->IsActive())
+					{
+					iIdle->Start(TCallBack(IdleFunction, this));
+					}
+				}
+			else
+				{
+				delete regBmp;
+				}
+			}
+		}
+#ifdef _DEBUG
+	else
+		{
+		RDebug::Printf("Example Rasterizer Error: CExampleRasterizer::EndBitmap() called for a bitmap that is not registered");
+		}
+#endif // _DEBUG
+	}
+
+/** Return a scanline from the passed extended bitmap given its bitmap id. 
+
+@see CFbsRasterizer::ScanLine()
+@see BeginBitmap()
+@see EndBitmap()
+ */
+const TUint32* CExampleRasterizer::ScanLine(TInt64 aBitmapId, const TPoint& aPixel, TInt aLength)
+	{
+	// Check that BeginBitmap() was called successfully and the passed bitmap was registered
+	// with this rasterizer
+	CRegisteredBitmap* regBmp = RegisteredBitmap(aBitmapId);
+	if (regBmp)
+		{
+		// Parameter check
+		if ((aPixel.iX < 0) || (aPixel.iX >= regBmp->iSizeInPixels.iWidth)
+			|| (aPixel.iY < 0) || (aPixel.iY >= regBmp->iSizeInPixels.iHeight)
+			|| (aLength > (regBmp->iSizeInPixels.iWidth - aPixel.iX))) // the requested length in pixels is greater than the declared width of the bitmap
+			{
+#ifdef _DEBUG
+			RDebug::Printf("Example Rasterizer Error: Invalid parameter passed to CExampleRasterizer::ScanLine()");
+#endif // _DEBUG
+			return NULL;
+			}
+		
+		TInt scanLineLength = CFbsBitmap::ScanLineLength(regBmp->iSizeInPixels.iWidth, regBmp->iDispMode);
+		return reinterpret_cast<TUint32*>(regBmp->Buffer() + (aPixel.iY * scanLineLength));
+		}
+#ifdef _DEBUG
+	else
+		{
+		RDebug::Printf("Example Rasterizer Error: CExampleRasterizer::ScanLine() called for a bitmap that is not registered");
+		}
+#endif // _DEBUG
+	
+	return NULL;
+	}
+
+/** Only MFbsRasterizerClearCache available, KErrExtensionNotSupported returned for all other cases.
+
+@see CFbsRasterizer::GetInterface()
+ */
+TInt CExampleRasterizer::GetInterface(TUid aInterfaceId, TAny*& aInterface)
+	{
+	aInterface = NULL;
+	TInt err = KErrNone;
+	
+	switch (aInterfaceId.iUid)
+		{
+		case KUidFbsRasterizerClearCache:
+			aInterface = static_cast<MFbsRasterizerClearCache*>(this);
+			break;
+		default:
+			err = KErrExtensionNotSupported;						
+			break;
+		}
+	
+	return err;
+	}
+
+
+/** Gets a bitmap that has been registered with this rasterizer.
+
+@param aBitmapId The ID of the bitmap to check for.
+
+@return A pointer to the registered bitmap if found, NULL otherwise.
+ */
+CExampleRasterizer::CRegisteredBitmap* CExampleRasterizer::RegisteredBitmap(TInt64 aBitmapId)
+	{
+	TDblQueIter<CRegisteredBitmap> iter(iRegisteredBmps);
+	while (CRegisteredBitmap* regBmp = iter++)
+		{
+		if (regBmp->iBitmapId == aBitmapId)
+			{
+			return regBmp;
+			}
+		}
+	return NULL;
+	}
+
+/** Gets a bitmap that has been recently used with this rasterizer.
+
+@param aBitmapId The ID of the bitmap to check for.
+
+@return A pointer to the recently used bitmap if found, NULL otherwise.
+ */
+CExampleRasterizer::CRegisteredBitmap* CExampleRasterizer::RecentBitmap(TInt64 aBitmapId)
+	{
+	TDblQueIter<CRegisteredBitmap> iter(iRecentBmps);
+	while (CRegisteredBitmap* regBmp = iter++)
+		{
+		if (regBmp->iBitmapId == aBitmapId)
+			{
+			return regBmp;
+			}
+		}
+	return NULL;
+	}
+
+/** Releases the memory for all the recently rasterized extended bitmaps kept in the cache.
+This function is called by the idle-time active object.
+
+@param aSelf A pointer to the rasterizer object.
+
+@return Zero to indicate that this function needn't be automatically called again.
+ */
+TInt CExampleRasterizer::IdleFunction(TAny* aPtr)
+	{
+	CExampleRasterizer* self = static_cast<CExampleRasterizer*>(aPtr);
+	while (!self->iRecentBmps.IsEmpty())
+		{
+		delete self->iRecentBmps.First();
+		}
+	self->iTotalRecentBmpSize = 0;
+	return 0;
+	}
+
+
+/** Constructor.
+ */
+CExampleRasterizer::CRegisteredBitmap::CRegisteredBitmap(TInt64 aBitmapId,
+	                                                     const TBitmapDesc& aBitmapDesc,
+	                                                     TInt aBufLength)
+	: iBitmapId(aBitmapId),
+	  iSizeInPixels(aBitmapDesc.iSizeInPixels),
+	  iDispMode(aBitmapDesc.iDispMode),
+	  iDataType(aBitmapDesc.iDataType),
+	  iBufLength(aBufLength)
+	{}
+
+/** Destructor.
+ */
+CExampleRasterizer::CRegisteredBitmap::~CRegisteredBitmap()
+	{
+	iLink.Deque();
+	}
+
+/** Rasterize a registered extended bitmap. The results are stored into the memory buffer embedded in this object.
+
+@param aReadStream A stream to read the proprietary data from.
+@param aRegionOfInterest The region within which scanline access requests will be made, if known.
+
+@return KErrNone on success, KErrNotSupported if the display mode is not supported,
+	KErrEof if there is not enough data to read, KErrArgument if aRegionOfInterest is out of bounds.
+ */
+TInt CExampleRasterizer::CRegisteredBitmap::Draw(RMemReadStream& aReadStream, const TRegion* aRegionOfInterest)
+	{
+	if (aRegionOfInterest && !aRegionOfInterest->IsContainedBy(iSizeInPixels))
+		{
+		return KErrArgument;
+		}
+	
+	// Read the three flag colours and the horizontal stripe flag from the data
+	TRgb colour1, colour2, colour3;
+	TUint8 horizontalStripe;
+	TRAPD(err,
+		aReadStream >> colour1;
+		aReadStream >> colour2;
+		aReadStream >> colour3;
+		aReadStream >> horizontalStripe;
+		);
+	if (err != KErrNone)
+		{
+		return err;
+		}
+	TUint32 c1, c2, c3;
+	TInt bpp;
+	switch (iDispMode)
+		{
+	case EGray256:
+		c1 = colour1.Gray256();
+		c2 = colour2.Gray256();
+		c3 = colour3.Gray256();
+		bpp = 1;
+		break;
+	case EColor64K:
+		c1 = colour1.Color64K();
+		c2 = colour2.Color64K();
+		c3 = colour3.Color64K();
+		bpp = 2;
+		break;
+	case EColor16MU:
+		c1 = colour1.Color16MU() | 0xFF000000;
+		c2 = colour2.Color16MU() | 0xFF000000;
+		c3 = colour3.Color16MU() | 0xFF000000;
+		bpp = 4;
+		break;
+	case EColor16MAP:
+		c1 = colour1.Color16MAP();
+		c2 = colour2.Color16MAP();
+		c3 = colour3.Color16MAP();
+		bpp = 4;
+		break;
+	default:
+		return KErrNotSupported;
+		}
+	
+	// If no region of interest is specified, rasterize the whole size of the bitmap
+	// Otherwise rasterize only the rectangles in the region of interest
+	// (Method takes no account of overlapping rectangles)
+	TRect wholeRect(iSizeInPixels);
+	TInt numRects;
+	const TRect* rects;
+	if (aRegionOfInterest)
+		{
+		numRects = aRegionOfInterest->Count();
+		rects = aRegionOfInterest->RectangleList();
+		// Pre-fill the flag with white so that areas outside the region of interest are white
+		// (this is not necessary but has been added to allow use of this rasterizer in BitGDI testing)
+		Mem::Fill(Buffer(), iBufLength, 0xFF);
+		}
+	else
+		{
+		// Set the only rect to be drawn to the whole size of the bitmap as no region of interest is specified
+		numRects = 1;
+		rects = &wholeRect;
+		}
+	
+	// Get the scanline length we should use for this display mode as the scanlines we draw must be 32-bit aligned
+	TInt scanLineLength = CFbsBitmap::ScanLineLength(iSizeInPixels.iWidth, iDispMode);
+	
+	if (horizontalStripe)
+		{
+		// Horizontal stripes
+		TInt stripeHeight = iSizeInPixels.iHeight / 3;
+		for (TInt r = 0; r < numRects; ++r)
+			{
+			for (TInt h = rects[r].iTl.iY; h < rects[r].iBr.iY; ++h)
+				{
+				for (TInt w = rects[r].iTl.iX; w < rects[r].iBr.iX; ++w)
+					{
+					if (h < stripeHeight)
+						{
+						Mem::Copy(Buffer() + (w * bpp) + (h * scanLineLength), &c1, bpp); // top
+						}
+					else if (h < iSizeInPixels.iHeight - stripeHeight)
+						{
+						Mem::Copy(Buffer() + (w * bpp) + (h * scanLineLength), &c2, bpp); // middle
+						}
+					else
+						{
+						Mem::Copy(Buffer() + (w * bpp) + (h * scanLineLength), &c3, bpp); // bottom
+						}
+					}
+				}
+			}
+		}
+	else
+		{
+		// Vertical stripes
+		TInt stripeWidth = iSizeInPixels.iWidth / 3;
+		for (TInt r = 0; r < numRects; ++r)
+			{
+			for (TInt h = rects[r].iTl.iY; h < rects[r].iBr.iY; ++h)
+				{
+				for (TInt w = rects[r].iTl.iX; w < rects[r].iBr.iX; ++w)
+					{
+					if (w < stripeWidth)
+						{
+						Mem::Copy(Buffer() + (w * bpp) + (h * scanLineLength), &c1, bpp); // left
+						}
+					else if (w < iSizeInPixels.iWidth - stripeWidth)
+						{
+						Mem::Copy(Buffer() + (w * bpp) + (h * scanLineLength), &c2, bpp); // middle
+						}
+					else
+						{
+						Mem::Copy(Buffer() + (w * bpp) + (h * scanLineLength), &c3, bpp); // right
+						}
+					}
+				}
+			}
+		}
+	
+	iWhole = (numRects == 1 && rects[0] == wholeRect);
+	return KErrNone;
+	}
+
+/** Gets a pointer to the pre-rendered buffer for this registered bitmap.
+ */
+TUint8* CExampleRasterizer::CRegisteredBitmap::Buffer()
+	{
+	// Adding one to "this" is the same as adding sizeof(*this) to the address of this object
+	// The result points to the pre-rendered buffer, located right after the instance variables
+	return reinterpret_cast<TUint8*>(this + 1);
+	}
+
+/** Implementation of MFbsRasterizerClearCache::ClearCache() to allow test code to 
+clear the cache of recently used extended bitmaps.
+ */
+void CExampleRasterizer::ClearCache()
+	{
+	while (!iRecentBmps.IsEmpty())
+		{
+		delete iRecentBmps.First();
+		}
+	iTotalRecentBmpSize = 0;
+	if (iIdle && iIdle->IsActive())
+		{
+		iIdle->Cancel();
+		}
+	}