--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/fbs/fontandbitmapserver/sfbs/BMPUTIL.CPP Tue Feb 02 01:47:50 2010 +0200
@@ -0,0 +1,693 @@
+// Copyright (c) 1995-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 <graphics/lookuptable.h>
+#include "fbsdefs.h"
+#include "UTILS.H"
+
+GLREF_C void Panic(TFbsPanic aPanic);
+
+/* Macros used in support of EColor16M mode bitmaps in TBitmapUtil.
+PTR2UINT, UINT2PTR defined to ease byte pointer arithmatic using
+the existing iWordPos word sized pointer.
+i MACROS redefine the meaning of members in the class for 16M use.
+All in the name of Binary Compatibility - adding 16M support but
+without wasting memory or increasing the size of this class's objects. */
+#define PTR2UINT(_ptr) reinterpret_cast<TUint32>(_ptr)
+#define UINT2PTR(_expr) reinterpret_cast<TUint32*>(_expr)
+#define iNUM_WASTE_BYTES iMask
+#define iSTART_OF_SCAN_LINE iWordPos
+#define iPIXEL_BYTE_OFFSET iPixelShift
+#define iPIXEL_ADDRESS UINT2PTR(PTR2UINT(iWordPos)+iPixelShift)
+
+
+/** Constructs a TBitmapUtil object for the specified bitmap.
+
+@param aBitmap The bitmap on which this TBitmapUtil will operate. */
+EXPORT_C TBitmapUtil::TBitmapUtil(CFbsBitmap* aBitmap):
+ iFbsBitmap(aBitmap), // Address of bitmap to navigate and modify.
+ iWordPos(NULL), // Non16M: Address of the word containing the bits
+ // of the current pixel.
+ // 16M: Redefined to iSTART_OF_SCAN_LINE - word address
+ // of the scan line containing the current pixel.
+ iMinWordPos(NULL), // Member holds the word address of the top left pixel.
+ iMaxWordPos(NULL), // Member holds address of the word following the last
+ // word in the last scan line of the bitmap.
+ iBpp(0), // Number of bits needed for each pixel's data.
+ iPixelShift(0), // Non16M: Right shift factor to convert pixel index
+ // to word index into scan line.
+ // 16M: Redefined to iPIXEL_BYTE_OFFSET - index to first
+ // byte in pixel from the start of the scan line.
+ iBitShift(0), // Non16M: Changing index of right shift require to
+ // move pixel bits into LSB of word.
+ // 16M: Not used, always 0
+ iMask(0), // Non16M: Mask of LSB required to hold
+ // pixel data eg. 16cols 0x0f
+ // 16M: Redefined to iNUM_WASTE_BYTES - number of
+ // padding bytes at end of scan line 0,3,6,9 as 16M
+ // scanlines are always multiples of 12 bytes.
+ iScanlineWordLength(0), // Number of 4-byte words in bitmap scan line
+ iWritten(EFalse)
+ {}
+
+/** Sets the current pixel position to the specified position and prepares
+the bitmap for access to its pixel data.
+
+This function must be called before using any of the other functions provided
+by this class, otherwise damage to data may occur. It must also be matched
+by a subsequent call to End().
+
+@pre The bitmap which was passed on class construction has been created and holds
+ a valid handle.
+@param aPosition The position to which the current pixel position should be
+set. */
+EXPORT_C void TBitmapUtil::Begin(const TPoint& aPosition)
+ {
+ ASSERT(iFbsBitmap);
+ iFbsBitmap->BeginDataAccess();
+ TSize bmpsize(iFbsBitmap->SizeInPixels());
+ ASSERT(bmpsize.iWidth > 0 && bmpsize.iHeight > 0);
+
+ iWritten = EFalse;
+
+ TDisplayMode dm=iFbsBitmap->DisplayMode();
+ TInt numBytesInScanline = CFbsBitmap::ScanLineLength(bmpsize.iWidth,dm);
+ switch(dm)
+ {
+ case EGray2:
+ iMask=1;
+ iPixelShift=5;
+ iBpp=1;
+ break;
+ case EGray4:
+ iMask=3;
+ iPixelShift=4;
+ iBpp=2;
+ break;
+ case EGray16:
+ case EColor16:
+ iMask=0xf;
+ iPixelShift=3;
+ iBpp=4;
+ break;
+ case EGray256:
+ case EColor256:
+ iMask=0xff;
+ iPixelShift=2;
+ iBpp=8;
+ break;
+ case EColor4K:
+ case EColor64K:
+ iMask=0xffff;
+ iPixelShift=1;
+ iBpp=16;
+ break;
+ /* Bit twiddling not used in the EColor16M, members redefined for
+ different use. */
+ case EColor16M:
+ iNUM_WASTE_BYTES = numBytesInScanline-(bmpsize.iWidth*3);
+ iPIXEL_BYTE_OFFSET=0;
+ iBpp=24; // Indicates 16M display mode, flag for member functions
+ // to switch functionality.
+ break;
+ case EColor16MU:
+ case EColor16MA:
+ case EColor16MAP:
+ iMask=0xffffffff;
+ iPixelShift=0;
+ iBpp=32;
+ break;
+ default: //shouldn't reach this point
+ Panic(EFbsBitmapInvalidMode);
+ }
+
+ iMinWordPos=(TUint32*)iFbsBitmap->DataAddress();
+ iScanlineWordLength = numBytesInScanline / 4;
+ iMaxWordPos = iMinWordPos + (bmpsize.iHeight * iScanlineWordLength);
+
+ TPoint correct(aPosition);
+ if(correct.iX<0) correct.iX=0;
+ if(correct.iY<0) correct.iY=0;
+ if(correct.iX>=bmpsize.iWidth) correct.iX=bmpsize.iWidth;
+ if(correct.iY>=bmpsize.iHeight) correct.iY=bmpsize.iHeight;
+ SetPos(correct);
+ }
+
+/** Sets the current pixel position to the specified position and prepares
+the bitmap for access to its pixel data.
+
+This function is deprecated. Use the other overload, Begin(const TPoint&).
+@deprecated
+
+@param aPosition The position to which the current pixel position should be
+set.
+@param aUtil Not used.
+@panic FBCLI 10 The bitmap's display mode is ERgb or ENone. */
+EXPORT_C void TBitmapUtil::Begin(const TPoint& aPosition, const TBitmapUtil& /*aUtil*/)
+ {
+ Begin(aPosition);
+ }
+
+/** Marks the end of the access to the bitmap data.
+This function must be called when finished using all the other functions
+provided by this class.
+
+There must be exactly one call to End() for each previous call to Begin()
+for a given TBitmapUtil object. */
+EXPORT_C void TBitmapUtil::End()
+ {
+ iFbsBitmap->EndDataAccess(!iWritten);
+ }
+
+
+
+/** Gets the value of the pixel at the current pixel position.
+
+In normal usage, the value returned will immediately be used as the parameter
+to a call to SetPixel(). To remove the overhead of constructing a TRgb, the
+function uses a TUint32 rather than a TRgb to hold an RGB value.
+
+@return The value of the pixel at the current pixel position. */
+EXPORT_C TUint32 TBitmapUtil::GetPixel() const
+ {
+ if (iBpp!=24)
+ // 1,2,4,8,12,16,32-bit pixels
+ return((*iWordPos>>iBitShift)&iMask);
+ else
+ {
+ // 24-bit pixels
+ // Due to machine word alignment requirement on ARM, need to copy
+ // pixel data at iWordPos a byte at a time if address is not aligned
+ // on a 4 byte boundary i.e. 1st or 2nd least sig. bits set.
+ if (iPIXEL_BYTE_OFFSET & 0x3)
+ {
+ TUint32 pixel = 0;
+ Mem::Copy(&pixel, iPIXEL_ADDRESS, 3);
+ return pixel;
+ }
+ else
+ return (*( iPIXEL_ADDRESS )&0x00ffffff);
+ }
+ }
+
+/** Sets the value of the pixel at the current pixel position.
+
+To remove the overhead of constructing a TRgb, the function uses a TUint32
+rather than a TRgb to hold an RGB value.
+
+@param aValue The value to which the pixel at the current pixel position is
+to be set. */
+EXPORT_C void TBitmapUtil::SetPixel(TUint32 aValue)
+ {
+ iWritten = ETrue;
+ if (iBpp!=24)
+ {
+ // 1,2,4,8,12,16,32-bit pixels
+ *iWordPos&=~(iMask<<iBitShift);
+ *iWordPos|=(aValue&iMask)<<iBitShift;
+ if(iBpp==32 && iFbsBitmap && iFbsBitmap->DisplayMode() == EColor16MU)
+ {
+ *iWordPos|= 0xff000000;
+ }
+ }
+ else
+ {
+ // 24-bit pixels
+ // Due to machine word alignment requirement on ARM, need to copy
+ // pixel data at iWordPos a byte at a time if address is not aligned
+ // on a 4 byte boundary i.e. 1st or 2nd least sig. bits set.
+ if (iPIXEL_BYTE_OFFSET & 0x3)
+ Mem::Copy(iPIXEL_ADDRESS, &aValue, 3);
+ else
+ {
+ *(iPIXEL_ADDRESS) &= ~0xffffff;
+ *(iPIXEL_ADDRESS) |= (aValue&0x00ffffff);
+ }
+ }
+ }
+
+/** Sets the value of the pixel at the current pixel position to that returned
+by aSource.GetPixel().
+
+@param aSource The TBitmapUtil of the source bitmap, whose pixel value is
+used to set the pixel at the current pixel position. */
+EXPORT_C void TBitmapUtil::SetPixel(const TBitmapUtil& aSource)
+ {
+ SetPixel(aSource.GetPixel());
+ }
+
+/** Sets a new current pixel position.
+
+@param aPosition The new current pixel position. */
+EXPORT_C void TBitmapUtil::SetPos(const TPoint& aPosition)
+ {
+ TSize bmpsize(iFbsBitmap->SizeInPixels());
+ TPoint correct(aPosition);
+
+ correct.iX%=bmpsize.iWidth;
+ correct.iY%=bmpsize.iHeight;
+ if(correct.iX<0) correct.iX+=bmpsize.iWidth;
+ if(correct.iY<0) correct.iY+=bmpsize.iHeight;
+
+ iWordPos=iMinWordPos;
+ iWordPos+=iScanlineWordLength*correct.iY;
+ if (iBpp!=24)
+ {
+ // 1,2,4,8,12,16,32-bit pixels
+ iWordPos+=correct.iX>>iPixelShift;
+ iBitShift=(correct.iX*iBpp)%32;
+ }
+ else
+ {
+ // 24-bit pixels
+ // iSTART_OF_SCAN_LINE (iWordPos) has correct value at this point
+ // iBitShift not used in 16M modes
+ iPIXEL_BYTE_OFFSET = correct.iX*3; // Byte offset in iY scan line to iX pixel
+ }
+}
+
+/** Decrements the x co-ordinate of the current pixel position. */
+EXPORT_C void TBitmapUtil::DecXPos()
+ {
+ if (iBpp!=24)
+ {
+ // 1,2,4,8,12,16,32-bit pixels
+ iBitShift-=iBpp;
+ if(iBitShift<0)
+ {
+ iBitShift+=32;
+ iWordPos--;
+ if(iWordPos<iMinWordPos) iWordPos=iMaxWordPos-1;
+ }
+ }
+ else
+ {
+ // 24-bit pixels
+ iPIXEL_BYTE_OFFSET -= 3;
+
+ // Scanline underflow?
+ if (iPIXEL_BYTE_OFFSET < 0)
+ {
+ iPIXEL_BYTE_OFFSET = (iScanlineWordLength*4)-iNUM_WASTE_BYTES-3;
+
+ // Bitmap underflow?
+ if (iSTART_OF_SCAN_LINE == iMinWordPos)
+ iSTART_OF_SCAN_LINE = iMaxWordPos-iScanlineWordLength;
+ else
+ iSTART_OF_SCAN_LINE -= iScanlineWordLength;
+ }
+ }
+ }
+
+/** Decrements the y co-ordinate of the current pixel position. */
+EXPORT_C void TBitmapUtil::DecYPos()
+ {
+ iWordPos-=iScanlineWordLength;
+ if(iWordPos<iMinWordPos) iWordPos+=iMaxWordPos-iMinWordPos;
+ }
+
+/** Increments the x co-ordinate of the current pixel position. */
+EXPORT_C void TBitmapUtil::IncXPos()
+ {
+ if (iBpp!=24)
+ {
+ // 1,2,4,8,12,16,32-bit pixels
+ iBitShift+=iBpp;
+ if(iBitShift>=32)
+ {
+ iBitShift=0;
+ iWordPos++;
+ if(iWordPos>=iMaxWordPos) iWordPos=iMinWordPos;
+ }
+ }
+ else
+ {
+ // 24-bit pixels
+ iPIXEL_BYTE_OFFSET += 3;
+
+ // Scanline overflow?
+ if (iPIXEL_BYTE_OFFSET >=
+ (iScanlineWordLength*4)-static_cast<TInt>(iNUM_WASTE_BYTES))
+ {
+ iPIXEL_BYTE_OFFSET = 0;
+ iSTART_OF_SCAN_LINE += iScanlineWordLength;
+
+ // Bitmap overflow?
+ if (iSTART_OF_SCAN_LINE >= iMaxWordPos)
+ iSTART_OF_SCAN_LINE = iMinWordPos;
+ }
+ }
+ }
+
+/** Increments the y co-ordinate of the current pixel position. */
+EXPORT_C void TBitmapUtil::IncYPos()
+ {
+ iWordPos+=iScanlineWordLength;
+ if(iWordPos>=iMaxWordPos) iWordPos-=iMaxWordPos-iMinWordPos;
+ }
+
+
+
+//
+// CDitherColor256
+//
+
+class TDitherColorError
+ {
+public:
+ inline TDitherColorError() {};
+ inline TDitherColorError(TInt aRed,TInt aGreen,TInt aBlue) : iRed(aRed), iGreen(aGreen), iBlue(aBlue) {}
+public:
+ TInt iRed;
+ TInt iGreen;
+ TInt iBlue;
+ };
+
+NONSHARABLE_CLASS(CDitherColor256) : public CBase
+ {
+public:
+ void ConstructL(TInt aLineWidth,const TColor256Util* aColorUtil = NULL);
+ void Reset();
+ void ConvertLine(TUint8* aDestination,TRgb* aSource);
+ ~CDitherColor256();
+private:
+ const TColor256Util* iColorUtil;
+ TInt iLineWidth;
+ TDitherColorError* iErrorBuffer;
+ TInt iErrorBufferLength;
+ };
+
+CDitherColor256::~CDitherColor256()
+ {
+ delete[] iErrorBuffer;
+ }
+
+void CDitherColor256::ConstructL(TInt aLineWidth,const TColor256Util* aColorUtil)
+ {
+ if(iErrorBufferLength<=aLineWidth)
+ {
+ delete[] iErrorBuffer;
+ iErrorBuffer = NULL;
+ }
+
+ if(!iErrorBuffer)
+ {
+ iErrorBuffer = new (ELeave) TDitherColorError[aLineWidth+1];
+ iErrorBufferLength = aLineWidth+1;
+ }
+
+ iLineWidth = aLineWidth;
+ if(!aColorUtil)
+ aColorUtil = TColor256Util::Default();
+ iColorUtil = aColorUtil;
+
+ Reset();
+ }
+
+void CDitherColor256::Reset()
+ {
+ Mem::FillZ(iErrorBuffer,iErrorBufferLength*sizeof(iErrorBuffer[0]));
+ }
+
+void CDitherColor256::ConvertLine(TUint8* aDestination,TRgb* aSource)
+ {
+ TUint8* dstLimit = aDestination+iLineWidth;
+ TDitherColorError* errorBuffer = iErrorBuffer;
+
+ TInt r = errorBuffer->iRed;
+ TInt g = errorBuffer->iGreen;
+ TInt b = errorBuffer->iBlue;
+ errorBuffer->iRed = 0;
+ errorBuffer->iGreen = 0;
+ errorBuffer->iBlue = 0;
+
+ while(aDestination<dstLimit)
+ {
+
+ {
+ TInt value = 0;
+
+ r += aSource->Red();
+ if(r>255)
+ value = 255;
+ else if(r>0)
+ value = r;
+
+ g += aSource->Green();
+ if(g>255)
+ value |= 255<<8;
+ else if(g>0)
+ value |= g<<8;
+
+ b += aSource->Blue();
+ if(b>255)
+ value |= 255<<16;
+ else if(b>0)
+ value |= b<<16;
+
+ aSource++;
+
+ value = iColorUtil->Color256(TRgb(value));
+ *(aDestination) = (TUint8)value;
+ value = iColorUtil->Color256(value).Value();
+
+ r -= value&0xFF;
+ g -= (value>>8)&0xFF;
+ b -= (value>>16)&0xFF;
+ }
+
+ {
+ TInt x = r>>2;
+ r = (r>>1)-(r>>3);
+ errorBuffer->iRed += r;
+ r += errorBuffer[1].iRed;
+ errorBuffer[1].iRed = x;
+
+ x = g>>2;
+ g = (g>>1)-(g>>3);
+ errorBuffer->iGreen += g;
+ g += errorBuffer[1].iGreen;
+ errorBuffer[1].iGreen = x;
+
+ x = b>>2;
+ b = (b>>1)-(b>>3);
+ errorBuffer->iBlue += b;
+ b += errorBuffer[1].iBlue;
+ errorBuffer[1].iBlue = x;
+
+ errorBuffer++;
+ }
+
+ aDestination++;
+ }
+ }
+
+//
+// CFbsColor256BitmapUtil
+//
+
+inline CFbsColor256BitmapUtil::CFbsColor256BitmapUtil()
+ { }
+
+/** Allocates and constructs a new 256 colour bitmap utility object, optionally
+specifying a palette.
+
+@param aPalette The palette of colours to use for the destination 256 colour
+bitmap. If there are more than 256 colours in the palette, only the first
+256 are used. May be NULL, in which case the system default 256 colour palette
+is used.
+@return The newly constructed object. */
+EXPORT_C CFbsColor256BitmapUtil* CFbsColor256BitmapUtil::NewL(const CPalette* aPalette)
+ {
+ CFbsColor256BitmapUtil* self = new (ELeave) CFbsColor256BitmapUtil;
+ CleanupStack::PushL(self);
+ if(aPalette)
+ {
+ self->iColor256Util = new (ELeave) TColor256Util;
+ self->iColor256Util->Construct(*aPalette);
+ }
+ // coverity[leave_without_push : FALSE]
+ // class member variables should not be pushed onto the cleanupstack
+ self->iDither = new (ELeave) CDitherColor256;
+ CleanupStack::Pop();
+ return self;
+ }
+
+CFbsColor256BitmapUtil::~CFbsColor256BitmapUtil()
+ {
+ delete iColor256Util;
+ delete iDither;
+ }
+
+/** Copies the contents of a source bitmap to a destination 256 colour bitmap.
+Both bitmaps must be the same size and the destination bitmap's display mode
+must be EColor256.
+
+@param aColor256Destination The destination to copy the bitmap to. Its display
+mode must be EColor256.
+@param aSource The source bitmap to copy from. Its display mode can be EColor16M,
+EColor64K, EColor4K or EColor256.
+@param aDither Specify EFloydSteinberg for Floyd-Steinberg dithering. By default,
+no dithering.
+@return KErrNone, if successful; otherwise, another of the system-wide error
+codes. KErrNotSupported is returned if aSource's display mode is not one of
+the values listed.
+@panic EFbsColor256UtilError Either aColor256Destination's display mode is
+not EColor256, or the two bitmaps are not the same size. */
+EXPORT_C TInt CFbsColor256BitmapUtil::CopyBitmap(CFbsBitmap* aColor256Destination,CFbsBitmap* aSource,TDither aDither)
+ {
+ aSource->BeginDataAccess();
+ aColor256Destination->BeginDataAccess();
+ const TDisplayMode sourceMode = aSource->DisplayMode();
+
+ TSize size(aSource->SizeInPixels());
+ TInt width = size.iWidth;
+ TInt height = size.iHeight;
+
+ // Check we are being askes to copy a bitmap to a color256 bitmap of the same size
+ if( aColor256Destination->DisplayMode()!=EColor256 || aColor256Destination->SizeInPixels()!=size )
+ Panic(EFbsColor256UtilError);
+
+ if( sourceMode!=EColor256 && sourceMode!=EColor4K && sourceMode!=EColor64K &&
+ sourceMode!=EColor16M && sourceMode!=EColor16MU && sourceMode!=EColor16MA && sourceMode!=EColor16MAP)
+ {
+ aSource->EndDataAccess(ETrue);
+ aColor256Destination->EndDataAccess(ETrue);
+ return KErrNotSupported;
+ }
+
+ // get a TColor256Utils to use
+ const TColor256Util* colorUtil = iColor256Util;
+ if(!colorUtil)
+ colorUtil = TColor256Util::Default();
+
+ if(aDither==EFloydSteinberg)
+ {
+ TRAPD(err,iDither->ConstructL(width,colorUtil));
+ if(err!=KErrNone)
+ {
+ aSource->EndDataAccess(ETrue);
+ aColor256Destination->EndDataAccess(ETrue);
+ return err;
+ }
+ }
+
+ TRgb* pixelBuffer = new TRgb[width];
+ if(!pixelBuffer)
+ {
+ aSource->EndDataAccess(ETrue);
+ aColor256Destination->EndDataAccess(ETrue);
+ return KErrNoMemory;
+ }
+
+ TUint8* src = (TUint8*)aSource->DataAddress();
+ TInt srcPitch = aSource->ScanLineLength(width,sourceMode);
+ TUint8* dst = (TUint8*)aColor256Destination->DataAddress();
+ TInt dstPitch = aColor256Destination->ScanLineLength(width,EColor256);
+
+ while(height--)
+ {
+ TInt i(0);
+ switch(sourceMode)
+ {
+ case EColor256:
+ for(i=0; i<width; i++)
+ pixelBuffer[i] = TRgb::Color256(((TUint8*)src)[i]);
+ break;
+ case EColor4K:
+ for(i=0; i<width; i++)
+ pixelBuffer[i] = TRgb::_Color4K(((TUint16*)src)[i]);
+ break;
+ case EColor64K:
+ for(i=0; i<width; i++)
+ pixelBuffer[i] = TRgb::_Color64K(((TUint16*)src)[i]);
+ break;
+ case EColor16M:
+ {
+ TUint8* data = src;
+ TUint8* dataLimit = data+width*3;
+ i = 0;
+ while(data<dataLimit)
+ {
+ TUint32 value = *(data++)<<16;
+ value += *(data++)<<8;
+ value += *(data++);
+ pixelBuffer[i++] = TRgb(value);
+ }
+ }
+ break;
+ case EColor16MU:
+ {
+ TInt32* data = reinterpret_cast<TInt32*> (src);
+ TInt32* dataLimit = data+width;
+ i = 0;
+ while(data<dataLimit)
+ {
+ pixelBuffer[i++] = TRgb::_Color16MU(*data++);
+ }
+ }
+ break;
+ case EColor16MA:
+ {
+ TInt32* data = reinterpret_cast<TInt32*> (src);
+ TInt32* dataLimit = data+width;
+ i = 0;
+ while(data<dataLimit)
+ {
+ pixelBuffer[i++] = TRgb::_Color16MA(*data++);
+ }
+ }
+ break;
+ case EColor16MAP:
+ {
+ // perform division of color channels by alpha.
+ TInt32* data = reinterpret_cast<TInt32*> (src);
+ TInt32* dataLimit = data+width;
+ while(data<dataLimit)
+ {
+ pixelBuffer[i++] = TRgb::_Color16MAP(*data++);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ if(aDither==EFloydSteinberg)
+ iDither->ConvertLine(dst,pixelBuffer);
+ else
+ colorUtil->Color256(dst,pixelBuffer,width);
+ dst += dstPitch;
+ src += srcPitch;
+ }
+
+ aSource->EndDataAccess(ETrue);
+ aColor256Destination->EndDataAccess(EFalse);
+
+ delete[] pixelBuffer;
+ return KErrNone;
+ }
+
+/**
+
+Required to ensure BC between NGage and 7.0S platforms.
+Function is exported at ordinal corresponding to where NGage platform
+has extended this library and must not be moved. */
+EXPORT_C void DummyReserved1()
+ {
+ User::Panic(_L("Dummy Function"), 0);
+ }
+
+