htiui/HtiServicePlugins/HtiScreenshotServicePlugin/src/HtiScreenshotServicePlugin.cpp
changeset 0 d6fe6244b863
child 3 2703485a934c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/htiui/HtiServicePlugins/HtiScreenshotServicePlugin/src/HtiScreenshotServicePlugin.cpp	Tue Feb 02 00:17:27 2010 +0200
@@ -0,0 +1,2274 @@
+/*
+* Copyright (c) 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:  SysInfoPlugin implementation
+*
+*/
+
+
+// INCLUDE FILES
+#include "HtiScreenshotServicePlugin.h"
+#include <HtiDispatcherInterface.h>
+#include <HTILogging.h>
+
+#include <ImageConversion.h>
+#include <EZCompressor.h>
+#include <hal.h>
+
+// CONSTANTS
+const static TUid KScreenshotServiceUid = {0x1020DEC3};
+
+enum TScreenCommands
+    {
+    // Normal screencapture
+    ECmdScreen                = 0x01,
+    ECmdScreenRegion          = 0x02,
+    ECmdScreenZip             = 0x03,
+    ECmdScreenRegionZip       = 0x04,
+
+    // Text recognition
+    ECmdTextRcg               = 0x10,
+    ECmdTextRcg_u             = 0x11,
+
+    // Text bitmap
+    ECmdTextBitmap            = 0x12,
+    ECmdTextBitmap_u          = 0x13,
+
+    // Screencapture in series
+    ECmdScreenSeries          = 0x21,
+    ECmdScreenRegionSeries    = 0x22,
+    ECmdScreenZipSeries       = 0x23,
+    ECmdScreenRegionZipSeries = 0x24,
+
+    // Selects the screen to use
+    ECmdSelectScreen          = 0x30,
+
+    // Gets the current screen size and orientation
+    ECmdScreenMode            = 0x3A,
+
+    // Screencapture on updated part of screen only
+    ECmdDeltaCaptureMask           = 0x80,
+    ECmdDeltaScreen                = 0x81,
+    ECmdDeltaScreenRegion          = 0x82,
+    ECmdDeltaScreenZip             = 0x83,
+    ECmdDeltaScreenRegionZip       = 0x84,
+    ECmdDeltaScreenReset           = 0x85
+    //ECmdDeltaScreenSeries          = 0xA1,
+    //ECmdDeltaScreenRegionSeries    = 0xA2,
+    //ECmdDeltaScreenZipSeries       = 0xA3,
+    //ECmdDeltaScreenRegionZipSeries = 0xA4
+    };
+
+enum TScreenResponse
+    {
+    ERspOk = 0xF0,
+    ERspNotFound = 0xF1
+    };
+
+enum THtiFontAttributes
+    {
+    EHtiFontAttBold = 0x01,
+    EHtiFontAttItalic = 0x02,
+    EHtiFontAttNotAA = 0x04,
+    EHtiFontAttPrintPositionFlag = 0x08,
+    EHtiFontAttPrintPositionValue = 0x10
+    };
+
+const static TInt KHtiFontAttSuperscriptValue = 0;
+const static TInt KHtiFontAttSubscriptValue = 1;
+
+//1 byte for cmd and 2*4 for 4 coordinates
+const static TInt KMinScreenRegionCmdLength = 9;
+const static TInt KScreenDisplayOffset = 1;
+const static TInt KScreenMIMEOffset = KScreenDisplayOffset + 1;
+const static TInt KRegionDisplayOffset = KMinScreenRegionCmdLength;
+const static TInt KRegionMIMEOffset = KRegionDisplayOffset + 1;
+
+
+const static TInt KSeriesDurationOffset = 1;
+const static TInt KSeriesIntervalOffset = KSeriesDurationOffset + 4;
+const static TInt KSeriesDisplayOffset = KSeriesIntervalOffset + 4;
+const static TInt KSeriesMIMEOffset = KSeriesDisplayOffset + 1;
+const static TInt KMinSeriesCmdLength = KSeriesMIMEOffset;
+
+const static TInt KRegionSeriesTlX = KSeriesDisplayOffset + 1;
+const static TInt KRegionSeriesTlY = KRegionSeriesTlX + 2;
+const static TInt KRegionSeriesBlX = KRegionSeriesTlY + 2;
+const static TInt KRegionSeriesBlY = KRegionSeriesBlX + 2;
+const static TInt KRegionSeriesMIMEOffset = KRegionSeriesBlY + 2;
+const static TInt KMinRegionSeriesCmdLength = KRegionSeriesMIMEOffset;
+
+const static TInt KDeltaResetCmdLength = 1;
+const static TInt KScreenModeCmdLength = 1;
+
+const static TInt KScreenNrOffset = 1;
+const static TInt KSelectScreenCmdLength = 2;
+
+_LIT( KSeriesShotPath, "c:\\Hti\\SeriesShot\\" );
+
+//errors' descriptions
+_LIT8( KErrDescrInvalid, "invalid arguments" );
+_LIT8( KErrDescrInvalidMode, "invalid color mode" );
+_LIT8( KErrDescrRegiontEmpty, "region is empty" );
+_LIT8( KErrDescrRegionNotNormailized, "region is not normalized" );
+_LIT8( KErrDescrRegionOutOfScreen, "region is out of screen" );
+_LIT8( KErrDescrUnknownCommand, "unknown command" );
+_LIT8( KErrDescrFailedConvert, "failed to convert to image format" );
+_LIT8( KErrDescrFailedCompress, "failed to compress" );
+_LIT8( KErrDescrMIMENotSupported, "MIME type not supported" );
+_LIT8( KErrDescrScreenNotSupported, "screen not supported" );
+
+_LIT( KScreenshotPanic, "Screenshot plug-in invalid state" );
+
+//_LIT(KS60Sans, "Series 60 Sans");
+//_LIT(KS60SansTitleBold, "Series 60 Sans TitleSmBd");
+
+//const TInt KFonHeighMin = 110;
+//const TInt KFonHeighMax = 190;
+/*
+// ----------------------------------------------------------------------------
+void CHtiScreenshotServicePlugin::InitFontCache()
+    {
+    //temporary
+    //just put harcoded data
+    //should be either external file or auto-defined based on logical fonts
+    //or some test app
+    TFontSpec fs;
+    fs.iFontStyle.SetBitmapType(EAntiAliasedGlyphBitmap);
+    //primary font
+    fs.iTypeface.iName = KS60Sans;
+    fs.iHeight = 161;
+    fs.iFontStyle.SetStrokeWeight(EStrokeWeightBold);
+    iFontCache.Append(fs);
+
+    fs.iFontStyle.SetStrokeWeight(EStrokeWeightNormal);
+
+    //Series 60 Sans TitleSmBd, 183
+    fs.iTypeface.iName = KS60SansTitleBold;
+    fs.iHeight = 183;
+    iFontCache.Append(fs);
+
+    //Series 60 Sans TitleSmBd, 172
+    fs.iTypeface.iName = KS60SansTitleBold;
+    fs.iHeight = 172;
+    iFontCache.Append(fs);
+
+    //Series 60 Sans,           122
+    fs.iTypeface.iName = KS60Sans;
+    fs.iHeight = 122;
+    iFontCache.Append(fs);
+    //Series 60 Sans,           116
+    fs.iTypeface.iName = KS60Sans;
+    fs.iHeight = 116;
+    iFontCache.Append(fs);
+
+    //Series 60 Sans TitleSmBd, 138
+    fs.iTypeface.iName = KS60SansTitleBold;
+    fs.iHeight = 138;
+    iFontCache.Append(fs);
+    }
+*/
+
+// ----------------------------------------------------------------------------
+TInt ImageDifferenceL( CFbsBitmap* aImage1, CFbsBitmap* aImage2,
+                       CFbsBitmap* &aResult, TRect &aRect )
+    {
+    HTI_LOG_TEXT( "ImageDifferenceL()" );
+
+    // By default return coordinates of the full image
+    aRect = TRect( 0, 0, aImage2->SizeInPixels().iWidth,
+                  aImage2->SizeInPixels().iHeight );
+
+//1. check that aImage1 and aImage2 are valid and can be compared
+    if ( aImage1 == NULL || aImage2 == NULL )
+        {
+        HTI_LOG_TEXT( "return KErrArgument" );
+        return KErrArgument;
+        }
+
+    if ( aImage1->SizeInPixels() != aImage2->SizeInPixels() )
+        {
+        HTI_LOG_TEXT( "return KErrGeneral (size)" );
+        return KErrGeneral;
+        }
+
+    if ( aImage1->DisplayMode() != aImage2->DisplayMode() )
+        {
+        HTI_LOG_TEXT( "return KErrGeneral (displaymode)" );
+        return KErrGeneral;
+        }
+
+
+//2. iterate through images from each border and compare to findout outline for diff region
+    TSize orgSize = aImage1->SizeInPixels();
+
+    TBitmapUtil srcBmpIterator1( aImage1 );
+    TBitmapUtil srcBmpIterator2( aImage2 );
+
+    srcBmpIterator1.Begin( TPoint( 0, 0 ) );
+    srcBmpIterator2.Begin( TPoint( 0, 0 ), srcBmpIterator1 );
+
+    TRect diffOutline = TRect( -1, -1, -1, -1 );
+
+    //2.1 top border iteration
+    TPoint c( 0,0 );
+    for ( ; c.iY < orgSize.iHeight && diffOutline.iTl.iY == -1; ++c.iY )
+        {
+        c.iX = 0;
+        srcBmpIterator1.SetPos( c );
+        srcBmpIterator2.SetPos( c );
+        for ( ; c.iX < orgSize.iWidth && diffOutline.iTl.iY == -1; ++c.iX )
+            {
+            if ( srcBmpIterator1.GetPixel() != srcBmpIterator2.GetPixel() )
+                {
+                diffOutline.iTl.iY = c.iY;
+                }
+
+            srcBmpIterator1.IncXPos();
+            srcBmpIterator2.IncXPos();
+            }
+        }
+
+    //2.2 bottom iteration
+    c.SetXY( 0, orgSize.iHeight - 1 );
+    for ( ; c.iY >= diffOutline.iTl.iY && diffOutline.iBr.iY == -1; --c.iY )
+        {
+        c.iX = 0;
+        srcBmpIterator1.SetPos( c );
+        srcBmpIterator2.SetPos( c );
+        for (; c.iX < orgSize.iWidth && diffOutline.iBr.iY == -1; ++c.iX )
+            {
+            if ( srcBmpIterator1.GetPixel() != srcBmpIterator2.GetPixel() )
+                {
+                diffOutline.iBr.iY = c.iY;
+                }
+
+            srcBmpIterator1.IncXPos();
+            srcBmpIterator2.IncXPos();
+            }
+        }
+
+    //2.3 left, goes in vertical lines
+    c.SetXY( 0, diffOutline.iTl.iY );
+    for ( ; c.iX < orgSize.iWidth && diffOutline.iTl.iX == -1; ++c.iX )
+        {
+        c.iY = diffOutline.iTl.iY;
+        srcBmpIterator1.SetPos( c );
+        srcBmpIterator2.SetPos( c );
+        for ( ; c.iY <= diffOutline.iBr.iY && diffOutline.iTl.iX == -1; ++c.iY )
+
+            {
+            if ( srcBmpIterator1.GetPixel() != srcBmpIterator2.GetPixel() )
+                {
+                diffOutline.iTl.iX = c.iX;
+                }
+
+            srcBmpIterator1.IncYPos();
+            srcBmpIterator2.IncYPos();
+            }
+        }
+    //2.4 right, goes in vertical lines
+    c.SetXY( orgSize.iWidth - 1, diffOutline.iTl.iY );
+    for ( ; c.iX >= diffOutline.iTl.iX && diffOutline.iBr.iX == -1; --c.iX )
+        {
+        c.iY = diffOutline.iTl.iY;
+        srcBmpIterator1.SetPos( c );
+        srcBmpIterator2.SetPos( c );
+        for ( ; c.iY <= diffOutline.iBr.iY && diffOutline.iBr.iX == -1; ++c.iY )
+
+            {
+            if ( srcBmpIterator1.GetPixel() != srcBmpIterator2.GetPixel() )
+                {
+                diffOutline.iBr.iX = c.iX;
+                }
+
+            srcBmpIterator1.IncYPos();
+            srcBmpIterator2.IncYPos();
+            }
+        }
+    srcBmpIterator2.End();
+    srcBmpIterator1.End();
+
+    //3. if there is some diff create CFbsBitmap in aResult and copy outlined image from aImage2
+    if ( diffOutline.iTl.iX == -1 &&
+         diffOutline.iTl.iY == -1 &&
+         diffOutline.iBr.iX == -1 &&
+         diffOutline.iBr.iY == -1 )
+        {
+        // No difference found
+        aRect = TRect( 0, 0, 0, 0 );
+        HTI_LOG_TEXT( "return KErrNotFound" );
+        return KErrNotFound;
+        }
+
+    aRect = diffOutline;
+
+    HTI_LOG_FORMAT( "Tlx - %d", aRect.iTl.iX );
+    HTI_LOG_FORMAT( "Tly - %d", aRect.iTl.iY );
+    HTI_LOG_FORMAT( "Bty - %d", aRect.iBr.iX );
+    HTI_LOG_FORMAT( "Bry - %d", aRect.iBr.iY );
+
+    // The bottom right co-ordinate is not included in the rectange
+    // (see TRect documentation) so we need to stretch the rectange
+    // for BitBlt to get the correct sized image.
+
+    TRect captureRect( diffOutline.iTl.iX, diffOutline.iTl.iY,
+                       diffOutline.iBr.iX + 1, diffOutline.iBr.iY + 1 );
+
+    aResult = new (ELeave) CFbsBitmap();
+    User::LeaveIfError( aResult->Create( captureRect.Size(), aImage2->DisplayMode() ) );
+    CleanupStack::PushL( aResult );
+
+    CFbsBitmapDevice* bmpDevice = CFbsBitmapDevice::NewL( aResult );
+    CleanupStack::PushL( bmpDevice );
+
+    CFbsBitGc* bmpCtx;
+    bmpDevice->CreateContext( bmpCtx );
+    bmpCtx->BitBlt( TPoint( 0, 0 ), aImage2, captureRect );
+
+    delete bmpCtx;
+    bmpCtx = NULL;
+
+    CleanupStack::PopAndDestroy(); // bmpDevice
+    CleanupStack::Pop(); // aResult
+
+    HTI_LOG_TEXT( "return KErrNone" );
+    return KErrNone;
+    }
+
+// ----------------------------------------------------------------------------
+CICLHandler::CICLHandler( CImageEncoder* aService, MICLObserver* anObserver ):
+    CActive( EPriorityStandard ),
+    iObserver( anObserver ),
+    iService( aService )
+    {
+    CActiveScheduler::Add( this );
+    }
+
+// ----------------------------------------------------------------------------
+CICLHandler::~CICLHandler()
+    {
+    Cancel();
+    }
+
+// ----------------------------------------------------------------------------
+void CICLHandler::Start()
+    {
+    SetActive();
+    }
+
+// ----------------------------------------------------------------------------
+void CICLHandler::RunL()
+    {
+    iObserver->ICLComplete( iStatus.Int() );
+    }
+
+// ----------------------------------------------------------------------------
+void CICLHandler::DoCancel()
+    {
+    iService->Cancel();
+    }
+
+/*
+// ----------------------------------------------------------------------------
+TInt CICLHandler::RunError(TInt aError)
+    {
+
+    }
+*/
+
+// ----------------------------------------------------------------------------
+// Create instance of concrete ECOM interface implementation
+CHtiScreenshotServicePlugin* CHtiScreenshotServicePlugin::NewL()
+    {
+    CHtiScreenshotServicePlugin* self = new (ELeave) CHtiScreenshotServicePlugin;
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    CleanupStack::Pop();
+    return self;
+    }
+
+// ----------------------------------------------------------------------------
+// Constructor
+CHtiScreenshotServicePlugin::CHtiScreenshotServicePlugin():
+    iScreen( NULL ),
+    iEncodedBitmap( NULL ),
+    iScreenDevice( NULL ),
+    iBitmapEncoder( NULL ),
+    iICLHandler( NULL ),
+    iCompress( EFalse ),
+    iDeltaCapture( EFalse ),
+    iPreviousBitmap( NULL )
+    {
+    }
+
+// ----------------------------------------------------------------------------
+CHtiScreenshotServicePlugin::~CHtiScreenshotServicePlugin()
+    {
+    HTI_LOG_FUNC_IN( "~CHtiScreenshotServicePlugin" );
+
+    iFontCache.Close();
+
+    delete iScreen;
+    delete iEncodedBitmap;
+
+    delete iICLHandler;
+    delete iBitmapEncoder;
+
+    delete iScreenDevice;
+
+    delete iSeriesShot;
+
+    if ( iPreviousBitmap )
+        delete iPreviousBitmap;
+
+    iWs.Close();
+    HTI_LOG_FUNC_OUT( "~CHtiScreenshotServicePlugin" );
+    }
+
+// ----------------------------------------------------------------------------
+// Second phase construction.
+void CHtiScreenshotServicePlugin::ConstructL()
+    {
+    HTI_LOG_FUNC_IN( "CHtiScreenshotServicePlugin::ConstructL" );
+    User::LeaveIfError( iWs.Connect() );
+
+    iScreenDevice = new ( ELeave ) CWsScreenDevice( iWs );
+    User::LeaveIfError( iScreenDevice->Construct() );
+
+    //InitFontCache();
+
+    iSeriesShot = CSeriesShot::NewL( this );
+
+    iPreviousBitmap = new ( ELeave ) CFbsBitmap;
+
+    //SelectEncoder( KImageTypeBMPUid );
+    HTI_LOG_FUNC_OUT( "CHtiScreenshotServicePlugin::ConstructL" );
+    }
+
+// ----------------------------------------------------------------------------
+TBool CHtiScreenshotServicePlugin::IsBusy()
+    {
+    if ( iICLHandler )
+        {
+        return iICLHandler->IsActive();
+        }
+
+    if ( iSeriesShot->IsOngoing() )
+        {
+        return ETrue;
+        }
+
+    return iEncodedBitmap != NULL;
+    }
+
+// ----------------------------------------------------------------------------
+inline TInt CHtiScreenshotServicePlugin::ParseInt16( const TUint8* aStart )
+    {
+    return aStart[0] + (aStart[1]<<8);
+    }
+
+// ----------------------------------------------------------------------------
+inline TInt CHtiScreenshotServicePlugin::ParseInt32( const TUint8* aStart )
+    {
+    return aStart[0] + (aStart[1]<<8) + (aStart[2]<<16) + (aStart[3]<<24);
+    }
+
+// ----------------------------------------------------------------------------
+void CHtiScreenshotServicePlugin::SendTextRecgReplyL(
+                                    const TBool aResult,
+                                    const TRect& aLocation,
+                                    const TInt aFontIndex)
+    {
+    HTI_LOG_FUNC_IN( "SendTextRecgReplyL" );
+    HBufC8* sendMsg = HBufC8::NewL( 10 );
+    CleanupStack::PushL( sendMsg );
+    if ( aResult )
+        {
+        sendMsg->Des().Append( ERspOk );
+        TUint16 co = aLocation.iTl.iX;
+        sendMsg->Des().Append( (TUint8*)(&co), 2 );
+        co = aLocation.iTl.iY;
+        sendMsg->Des().Append( (TUint8*)(&co), 2 );
+        co = aLocation.iBr.iX;
+        sendMsg->Des().Append( (TUint8*)(&co), 2 );
+        co = aLocation.iBr.iY;
+        sendMsg->Des().Append( (TUint8*)(&co), 2 );
+        sendMsg->Des().Append( (TUint8)aFontIndex );
+        }
+    else
+        {
+        sendMsg->Des().Append( ERspNotFound );
+        sendMsg->Des().AppendFill( 0, 5 );
+        }
+
+    User::LeaveIfError( iDispatcher->DispatchOutgoingMessage(
+                            sendMsg,
+                            KScreenshotServiceUid) );
+
+    CleanupStack::Pop();
+    HTI_LOG_FUNC_OUT( "SendTextRecgReplyL" );
+    }
+
+// ----------------------------------------------------------------------------
+void CHtiScreenshotServicePlugin::CopyUnicode( TDes & aTo, const TDesC8& aFrom )
+{
+    HTI_LOG_FUNC_IN( "CHtiScreenshotServicePlugin::CopyUnicode" );
+    //aTo.Copy( reinterpret_cast<const TUint16*>(aFrom.Ptr()), aFrom.Length() );
+    TInt len = aFrom.Length()>>1;
+    aTo.SetLength( len );
+    for ( TInt i = 0; i < len; ++i )
+    {
+        aTo[i] = (TUint16)aFrom[i<<1] + (((TUint16)aFrom[(i<<1)+1])<<8);
+    }
+    HTI_LOG_FUNC_OUT( "CHtiScreenshotServicePlugin::CopyUnicode" );
+}
+
+// ----------------------------------------------------------------------------
+TInt CHtiScreenshotServicePlugin::ParseString( const TDesC8& aRequest,
+                                        TInt anOffset,
+                                        TBool aUnicode,
+                                        TDes& aResult)
+    {
+    HTI_LOG_FUNC_IN( "CHtiScreenshotServicePlugin::ParseString" );
+    //validate parameters
+    //if offset outside the string return empty string
+    if ( anOffset >= aRequest.Size() )
+        {
+        return anOffset;
+        }
+
+    TInt len = aRequest[ anOffset ];
+    HTI_LOG_FORMAT( "len %d", len );
+
+    if ( len> aResult.MaxLength() )
+        {
+        return KErrBadDescriptor;
+        }
+
+    TInt nextOffset = ( aUnicode ? len * 2 : len ) + anOffset + 1;
+    HTI_LOG_FORMAT( "nextOffset %d", nextOffset );
+    HTI_LOG_FORMAT( "reqSize %d", aRequest.Size() );
+    if ( nextOffset > aRequest.Size() )
+        {
+        return KErrArgument;
+        }
+
+    if ( aUnicode )
+        {
+        //const TUint8* ptr = aRequest.Mid( anOffset + 1, len * 2 ).Ptr();
+        //aResult.Copy( (const TUint16*)ptr, len );
+        CopyUnicode( aResult, aRequest.Mid( anOffset + 1, len * 2 ) );
+        }
+    else
+        {
+        aResult.Copy( aRequest.Mid( anOffset + 1, len ) );
+        }
+
+    HTI_LOG_FUNC_OUT( "CHtiScreenshotServicePlugin::ParseString" );
+    return nextOffset;
+    }
+
+// ----------------------------------------------------------------------------
+TInt CHtiScreenshotServicePlugin::ParseFontSpec( const TDesC8& aRequest,
+                    TInt anOffset,
+                    TBool aUnicode,
+                    TFontSpec& aResult)
+    {
+    if ( anOffset >= aRequest.Size() )
+        {
+        return KErrArgument;
+        }
+
+    //get font name
+    TPtr tn = aResult.iTypeface.iName.Des();
+    TInt offset = ParseString( aRequest,
+                    anOffset,
+                    aUnicode,
+                    tn );
+
+    if ( offset > anOffset )
+        {
+        HTI_LOG_DES(aResult.iTypeface.iName);
+        //check that we have valid descr
+        if ( offset + 2 <= aRequest.Size() )
+            {
+            aResult.iHeight = ParseInt16( aRequest.Ptr() + offset );
+            HTI_LOG_FORMAT( "font height %d", aResult.iHeight );
+            //check style byte
+            TUint8 style = aRequest[ offset + 2 ];
+            HTI_LOG_FORMAT( "style %d", style );
+
+            //stroke bit
+            if ( style & EHtiFontAttBold )
+                {
+                aResult.iFontStyle.SetStrokeWeight(EStrokeWeightBold);
+                }
+            else
+                {
+                aResult.iFontStyle.SetStrokeWeight(EStrokeWeightNormal);
+                }
+            //posture
+            if ( style & EHtiFontAttItalic )
+                {
+                aResult.iFontStyle.SetPosture(EPostureItalic);
+                }
+            else
+                {
+                aResult.iFontStyle.SetPosture(EPostureUpright);
+                }
+            //bitmap glyph type
+            if ( style & EHtiFontAttNotAA )
+                {
+                aResult.iFontStyle.SetBitmapType( EMonochromeGlyphBitmap );
+                }
+            else
+                {
+                aResult.iFontStyle.SetBitmapType( EAntiAliasedGlyphBitmap );
+                }
+            //print position
+            if ( style & EHtiFontAttPrintPositionFlag )
+                {
+                TInt printPos = style & EHtiFontAttPrintPositionValue;
+                if ( printPos == KHtiFontAttSuperscriptValue )
+                    {
+                    aResult.iFontStyle.SetPrintPosition( EPrintPosSuperscript );
+                    }
+                else if ( printPos == KHtiFontAttSubscriptValue )
+                    {
+                    aResult.iFontStyle.SetPrintPosition( EPrintPosSubscript );
+                    }
+                }
+            else
+                {
+                aResult.iFontStyle.SetPrintPosition( EPrintPosNormal );
+                }
+            return offset + 3;
+            }
+        else
+            {
+            return KErrArgument;
+            }
+        }
+    else
+        {
+        return offset<0?offset:KErrArgument;
+        }
+    }
+
+// ----------------------------------------------------------------------------
+void CHtiScreenshotServicePlugin::ProcessTextRcgMessageL(
+                                    const TDesC8& aMessage)
+    {
+    HTI_LOG_FUNC_IN( "CHtiScreenshotServicePlugin::ProcessTextRcgMessageL" );
+    TBool unicode = aMessage[0] & 0x1;
+
+    TBuf<0xFF> text;
+
+    TInt offset = ParseString(aMessage, 1, unicode, text);
+
+    HTI_LOG_FORMAT( "offset %d ", offset );
+    if ( offset > 1 )
+        {
+        HTI_LOG_DES(text);
+
+        if ( offset + 1 < aMessage.Size() )
+            {
+            TInt numOfFonts = aMessage[ offset ];
+            HTI_LOG_FORMAT( "num of fonts %d", numOfFonts );
+            iFontCache.Reset();
+            TInt nextOffset  = offset + 1;
+            for ( TInt i = 0; i < numOfFonts; ++i )
+                {
+                TFontSpec fontSpec;
+                nextOffset = ParseFontSpec(aMessage,
+                                            nextOffset,
+                                            unicode,
+                                            fontSpec);
+                if ( nextOffset < 0 )
+                    {
+                    iDispatcher->DispatchOutgoingErrorMessage(
+                        nextOffset,
+                        KErrDescrInvalid,
+                        KScreenshotServiceUid);
+                    return;
+                    }
+                else
+                    {
+                    iFontCache.Append( fontSpec );
+                    }
+                }
+
+            //parameters parsing END
+            //get screenshot
+            TRect empty;
+            CreateBitmapL( empty, ENone );
+
+            //call text rcg routines
+            TInt fontIndex;
+            TRect resultRect;
+
+            //recognize text using fonts from iFontCache
+            TBool result = RecognizeTextL( text, resultRect, fontIndex );
+
+            SendTextRecgReplyL( result, resultRect, fontIndex );
+
+            delete iScreen;
+            iScreen = NULL;
+            }
+        else
+            {
+            //no fonts data
+            iDispatcher->DispatchOutgoingErrorMessage(
+                        KErrArgument,
+                        KErrDescrInvalid,
+                        KScreenshotServiceUid);
+
+            }
+        }
+    else if ( offset == 1 )
+        {
+        //empty text
+        iDispatcher->DispatchOutgoingErrorMessage(
+                        KErrArgument,
+                        KErrDescrInvalid,
+                        KScreenshotServiceUid);
+        }
+    else
+        {
+        //error
+        iDispatcher->DispatchOutgoingErrorMessage(
+                        offset,
+                        KErrDescrInvalid,
+                        KScreenshotServiceUid);
+        }
+    HTI_LOG_FUNC_OUT( "CHtiScreenshotServicePlugin::ProcessTextRcgMessageL" );
+    }
+
+// ----------------------------------------------------------------------------
+void CHtiScreenshotServicePlugin::ProcessTextBitmapMessageL(
+                                    const TDesC8& aMessage)
+    {
+    HTI_LOG_FUNC_IN( "CHtiScreenshotServicePlugin::ProcessTextBitmapMessageL" );
+    TBool unicode = aMessage[0] & 0x1;
+
+    TDisplayMode displayMode = ENone;
+    //check display
+    if ( aMessage.Size() > KScreenDisplayOffset )
+        {
+        displayMode = (TDisplayMode)aMessage[KScreenDisplayOffset];
+        if ( displayMode >= EColorLast )
+            {
+            iDispatcher->DispatchOutgoingErrorMessage(
+                            KErrArgument,
+                            KErrDescrInvalidMode,
+                            KScreenshotServiceUid);
+            return;
+            }
+        }
+
+    //check mime
+    TPtrC8 mime;
+    if ( aMessage[KScreenMIMEOffset] > 0 &&
+        ( aMessage[KScreenMIMEOffset] + KScreenMIMEOffset+1 ) < aMessage.Size() )
+        {
+        mime.Set( aMessage.Mid(KScreenMIMEOffset+1, aMessage[KScreenMIMEOffset] ) );
+        if ( !IsMIMETypeSupported( mime ) )
+            {
+            iDispatcher->DispatchOutgoingErrorMessage(
+                            KErrArgument,
+                            KErrDescrMIMENotSupported,
+                            KScreenshotServiceUid);
+            return;
+            }
+        }
+    else if ( aMessage[KScreenMIMEOffset] != 0 )
+        {
+        iDispatcher->DispatchOutgoingErrorMessage(
+                        KErrArgument,
+                        KErrDescrInvalidMode,
+                        KScreenshotServiceUid);
+        return;
+        }
+
+    TBuf<0xFF> text;
+    TInt preTextOffset = KScreenMIMEOffset + aMessage[KScreenMIMEOffset] + 1;
+    TInt offset = ParseString( aMessage, preTextOffset, unicode, text );
+
+    HTI_LOG_FORMAT( "offset %d ", offset );
+    if ( offset == preTextOffset )
+        {
+        //empty text
+        iDispatcher->DispatchOutgoingErrorMessage(
+                        KErrArgument,
+                        KErrDescrInvalid,
+                        KScreenshotServiceUid);
+        }
+    else if ( offset < preTextOffset )
+        {
+        //error
+        iDispatcher->DispatchOutgoingErrorMessage(
+                        offset,
+                        KErrDescrInvalid,
+                        KScreenshotServiceUid);
+        }
+
+    HTI_LOG_DES(text);
+    TFontSpec fontSpec;
+    offset = ParseFontSpec(aMessage,
+                            offset,
+                            unicode,
+                            fontSpec);
+    if ( offset < 0 )
+        {
+        iDispatcher->DispatchOutgoingErrorMessage(
+            offset,
+            KErrDescrInvalid,
+            KScreenshotServiceUid);
+
+        return;
+        }
+
+    //check colors
+    HTI_LOG_TEXT( "check colors" );
+    if ( offset + 2*4 != aMessage.Size() )
+        {
+        iDispatcher->DispatchOutgoingErrorMessage(
+            offset,
+            KErrDescrInvalid,
+            KScreenshotServiceUid);
+        return;
+        }
+
+    //extract colors
+    TUint32 fgColor = ParseInt32( aMessage.Ptr() + offset );
+    TUint32 bgColor = ParseInt32( aMessage.Ptr() + offset + 4 );
+    HTI_LOG_FORMAT( "FG color %d", fgColor );
+    HTI_LOG_FORMAT( "BG color %d", bgColor );
+
+    //END parsing
+    //generate and return bitmap
+    CFont* useFont;
+
+    User::LeaveIfError( iScreenDevice->GetNearestFontToDesignHeightInPixels(
+                            useFont, fontSpec ) );
+
+    TDisplayMode dm = displayMode==ENone || displayMode==0?
+                                        iScreenDevice->DisplayMode():
+                                        displayMode;
+
+
+    delete iScreen;
+    iScreen = NULL;
+    iScreen = CHtiTextRcg::GetTextBitmapL(
+                            text,
+                            useFont,
+                            TRgb( fgColor ),
+                            TRgb( bgColor ),
+                            dm );
+
+    iScreenDevice->ReleaseFont( useFont );
+
+    //Encode iBitmap
+    iCompress = EFalse;
+    if ( mime.Length() == 0 )
+        {
+        EncodeBitmapL(); //use default encoder BMP
+        }
+    else
+        {
+        HTI_LOG_DES( mime );
+        EncodeBitmapL( mime );
+        }
+
+    HTI_LOG_FUNC_OUT( "CHtiScreenshotServicePlugin::ProcessTextBitmapMessageL" );
+    }
+
+/*
+// ----------------------------------------------------------------------------
+TBool CHtiScreenshotServicePlugin::RecognizeTextAllL(
+                        const TDesC& aText,
+                        TPoint& aResult)
+    {
+    HTI_LOG_FUNC_IN( "CHtiScreenshotServicePlugin::RecognizeTextAllL" );
+
+    TSize screenRect = iScreenDevice->SizeInPixels();
+    TInt nofTF = iScreenDevice->NumTypefaces();
+    HTI_LOG_FORMAT( "Number of typefaces %d", nofTF );
+    TBool returnValue = EFalse;
+    for ( TInt i = 0; i < nofTF; ++i )
+        {
+        TTypefaceSupport tf;
+        iScreenDevice->TypefaceSupport(tf, i);
+
+        HTI_LOG_DES(tf.iTypeface.iName);
+
+        if ( tf.iIsScalable )
+            {
+            //iterate throuh heighes
+
+            HTI_LOG_FORMAT( "num of heighs %d", tf.iNumHeights );
+            HTI_LOG_FORMAT( "min h in tw %d", tf.iMinHeightInTwips );
+            HTI_LOG_FORMAT( "max h in tw %d", tf.iMaxHeightInTwips );
+            HTI_LOG_FORMAT( "scalable %d", tf.iIsScalable );
+
+            HTI_LOG_TEXT( "-----------------------" );
+
+            TInt minHeight = Max(tf.iMinHeightInTwips, KFonHeighMin );
+            TInt maxHeight = Min(tf.iMaxHeightInTwips, KFonHeighMax );
+
+            if ( minHeight > maxHeight )
+                {
+                continue;
+                }
+
+            for ( TInt v = 0; v < 2; ++v )
+                {
+                TInt lastFontHeight = 0;
+                for ( TInt fh = minHeight; fh <= maxHeight; ++fh )
+                    {
+                    TFontSpec fs( tf.iTypeface.iName, fh );
+                    fs.iFontStyle.SetBitmapType( EAntiAliasedGlyphBitmap );
+                    switch ( v )
+                        {
+                        case 1:
+                            {
+                            fs.iFontStyle.SetStrokeWeight(EStrokeWeightBold);
+                            HTI_LOG_TEXT( "BOLD" );
+                            }
+                            break;
+                        default:
+                            {
+                            HTI_LOG_TEXT( "DEFAULT" );
+                            }
+                        }
+                    HTI_LOG_FORMAT( "hh  %d", fh );
+
+                    CFont* useFont = NULL;
+
+                    iScreenDevice->GetNearestFontToDesignHeightInTwips(useFont, fs);
+
+                    if ( screenRect.iHeight < useFont->HeightInPixels() ||
+                         screenRect.iWidth < useFont->MaxNormalCharWidthInPixels()
+                        )
+                        {
+                        break;
+                        }
+
+                    if ( useFont->HeightInPixels() == lastFontHeight )
+                        {
+                        continue;
+                        }
+
+
+                    lastFontHeight = useFont->HeightInPixels();
+
+                    returnValue = iTextRcg.RecognizeTextL(
+                                                iScreen,
+                                                aText,
+                                                useFont,
+                                                aResult);
+                    //HTI_LOG_TEXT( "ReleaseFont" );
+                    iScreenDevice->ReleaseFont(useFont);
+
+                    if ( returnValue )
+                        {
+                        HTI_LOG_TEXT( "Found" );
+                        HTI_LOG_DES( aText );
+                        HTI_LOG_DES( tf.iTypeface.iName );
+                        HTI_LOG_FORMAT( "Font height in twips %d", fh );
+                        HTI_LOG_FORMAT( "X %d", aResult.iX );
+                        HTI_LOG_FORMAT( "Y %d", aResult.iY );
+                        return returnValue;
+                        }
+                    }
+                }
+            }
+        else
+            {//non scal. font
+            TFontSpec fs( tf.iTypeface.iName,0 ); //height doesn't matter for
+                                                //not scalable font
+
+            CFont* useFont = NULL;
+            //HTI_LOG_TEXT( "GetFont" );
+            iScreenDevice->GetNearestFontToDesignHeightInTwips( useFont, fs );
+
+            returnValue = iTextRcg.RecognizeTextL(
+                                        iScreen,
+                                        aText,
+                                        useFont,
+                                        aResult );
+            //HTI_LOG_TEXT( "ReleaseFont" );
+            iScreenDevice->ReleaseFont( useFont );
+
+            if ( returnValue )
+                {
+                HTI_LOG_TEXT( "Found" );
+                HTI_LOG_DES( aText );
+                HTI_LOG_DES(tf.iTypeface.iName );
+                HTI_LOG_FORMAT( "X %d", aResult.iX );
+                HTI_LOG_FORMAT( "Y %d", aResult.iY );
+                return returnValue;
+                }
+            }
+        }
+
+    //
+
+    HTI_LOG_FUNC_OUT( "CHtiScreenshotServicePlugin::RecognizeTextAllL" );
+    //return returnValue;
+    return EFalse;
+    }
+*/
+
+// ----------------------------------------------------------------------------
+TBool CHtiScreenshotServicePlugin::RecognizeTextL(
+                        const TDesC& aText,
+                        TRect& aResult,
+                        TInt& aFontIndex)
+    {
+    HTI_LOG_FUNC_IN( "CHtiScreenshotServicePlugin::RecognizeTextL" );
+
+    TSize screenRect = iScreenDevice->SizeInPixels();
+    TInt cacheSize = iFontCache.Count();
+    HTI_LOG_FORMAT( "Cache size %d", cacheSize );
+
+    TBool returnValue = EFalse;
+    for ( TInt i = 0; i < cacheSize; ++i )
+        {
+        CFont* useFont = NULL;
+
+        User::LeaveIfError(iScreenDevice->GetNearestFontToDesignHeightInPixels(
+                                useFont, iFontCache[i] ) );
+        if ( iFontCache[i].iFontStyle.BitmapType()==EAntiAliasedGlyphBitmap )
+            {
+            iTextRcg.SetHint( EHintEdge );
+            }
+        else
+            {
+            iTextRcg.SetHint( EHintNone );
+            }
+
+        //check that font in valid size
+        if ( screenRect.iHeight < useFont->HeightInPixels() ||
+             screenRect.iWidth < useFont->MaxNormalCharWidthInPixels()
+            )
+            {
+            break;
+            }
+
+        returnValue = iTextRcg.RecognizeTextL( iScreen, aText, useFont,
+                aResult );
+
+        iScreenDevice->ReleaseFont( useFont );
+
+        if ( returnValue )
+            {
+            HTI_LOG_FORMAT( "Found! fontIndex %d", i );
+            HTI_LOG_DES( aText );
+            HTI_LOG_DES( iFontCache[i].iTypeface.iName );
+            HTI_LOG_FORMAT( "TL X %d", aResult.iTl.iX );
+            HTI_LOG_FORMAT( "TL Y %d", aResult.iTl.iY );
+            HTI_LOG_FORMAT( "BR X %d", aResult.iBr.iX );
+            HTI_LOG_FORMAT( "BR Y %d", aResult.iBr.iY );
+            aFontIndex = i;
+            return returnValue;
+            }
+        }
+
+    HTI_LOG_FUNC_OUT( "CHtiScreenshotServicePlugin::RecognizeTextL" );
+    return EFalse;
+    }
+
+/*
+TBool CHtiScreenshotServicePlugin::RecognizeTextL(
+                        const TDesC& aText,
+                        const TDesC& aTypeface,
+                        TPoint& aResult)
+    {
+    HTI_LOG_FUNC_IN( "RecognizeTextL typeface" );
+    //const CFont* fontUsed = NULL;// AknLayoutUtils::FontFromName(aTypeface);
+    CFont* useFont = NULL;
+    TFontSpec fs(aTypeface, 0);
+
+    iScreenDevice->GetNearestFontInTwips(useFont, fs);
+
+    TBool returnValue = iTextRcg.RecognizeTextL(iScreen, aText, useFont, aResult);
+
+HTI_LOG_FUNC_OUT( "RecognizeTextL" );
+    return returnValue;
+}
+*/
+
+// ----------------------------------------------------------------------------
+void CHtiScreenshotServicePlugin::ProcessMessageL(const TDesC8& aMessage,
+                THtiMessagePriority /*aPriority*/)
+    {
+    HTI_LOG_FUNC_IN( "CHtiScreenshotServicePlugin::ProcessMessage");
+
+    if ( iICLHandler )
+        {
+        if ( iICLHandler->IsActive() || iEncodedBitmap)
+            {
+            User::Leave( KErrInUse );
+            }
+        }
+
+    if ( iSeriesShot->IsOngoing() )
+        User::Leave( KErrInUse );
+
+    // update the current screen mode
+    TPixelsAndRotation currentPixelsAndRotation;
+    iScreenDevice->GetScreenModeSizeAndRotation(
+            iScreenDevice->CurrentScreenMode(), currentPixelsAndRotation );
+    iScreenDevice->SetScreenSizeAndRotation( currentPixelsAndRotation );
+
+    if ( aMessage.Length() > 0 )
+        {
+        // set/reset delta capture status
+        iDeltaCapture = ( aMessage[0] & ECmdDeltaCaptureMask ) ? ETrue : EFalse;
+        if ( iDeltaCapture )
+            {
+            HTI_LOG_TEXT( "DeltaCapture ETrue" );
+            }
+
+        //if text recogn call separate handler
+        if ( aMessage[0] == ECmdTextRcg ||
+             aMessage[0] == ECmdTextRcg_u )
+            {
+            ProcessTextRcgMessageL( aMessage );
+            return;
+            }
+        else if ( aMessage[0] == ECmdTextBitmap ||
+                  aMessage[0] == ECmdTextBitmap_u )
+            {
+            ProcessTextBitmapMessageL( aMessage );
+            return;
+            }
+
+        iCompress = ( aMessage[0] == ECmdScreenZip ) ||
+                    ( aMessage[0] == ECmdScreenRegionZip ) ||
+                    ( aMessage[0] == ECmdScreenZipSeries ) ||
+                    ( aMessage[0] == ECmdScreenRegionZipSeries ) ||
+                    ( aMessage[0] == ECmdDeltaScreenZip ) ||
+                    ( aMessage[0] == ECmdDeltaScreenRegionZip );
+
+        HTI_LOG_FORMAT( "cmd 0x%x", aMessage[0] );
+        TPtrC8 mime;
+
+        switch ( aMessage[0] )
+            {
+            case ECmdScreen:
+            case ECmdScreenZip:
+            case ECmdDeltaScreen:
+            case ECmdDeltaScreenZip:
+                {
+                TRect empty;
+                TDisplayMode displayMode = ENone;
+                //check display
+                if ( aMessage.Length() > KScreenDisplayOffset )
+                    {
+                    displayMode = ( TDisplayMode ) aMessage[KScreenDisplayOffset];
+                    if ( displayMode >= EColorLast )
+                        {
+                        iDispatcher->DispatchOutgoingErrorMessage(
+                                        KErrArgument,
+                                        KErrDescrInvalidMode,
+                                        KScreenshotServiceUid );
+                        return;
+                        }
+                    }
+
+                CreateBitmapL( empty, displayMode );
+                //check mime
+                if ( aMessage.Length() > KScreenMIMEOffset )
+                    {
+                    mime.Set( aMessage.Mid( KScreenMIMEOffset ) );
+                    if ( !IsMIMETypeSupported( mime ) )
+                        {
+                        iDispatcher->DispatchOutgoingErrorMessage(
+                                        KErrArgument,
+                                        KErrDescrMIMENotSupported,
+                                        KScreenshotServiceUid );
+                        return;
+                        }
+                    }
+                }
+                break;
+
+            case ECmdScreenRegion:
+            case ECmdScreenRegionZip:
+            case ECmdDeltaScreenRegion:
+            case ECmdDeltaScreenRegionZip:
+                {
+                if ( aMessage.Length() >= KMinScreenRegionCmdLength )
+                    {
+                    TRect region;
+                    const TUint8* ptr = aMessage.Ptr();
+                    region.iTl.iX = ParseInt16( ptr + 1 );
+                    region.iTl.iY = ParseInt16( ptr + 3 );
+                    region.iBr.iX = ParseInt16( ptr + 5 );
+                    region.iBr.iY = ParseInt16( ptr + 7 );
+
+                    //check empty and normmalizaed
+                    if ( !region.IsNormalized() )
+                        {
+                        iDispatcher->DispatchOutgoingErrorMessage(
+                                        KErrArgument,
+                                        KErrDescrRegionNotNormailized,
+                                        KScreenshotServiceUid );
+                        return;
+                        }
+
+                    if ( region.IsEmpty() )
+                        {
+                        iDispatcher->DispatchOutgoingErrorMessage(
+                                        KErrArgument,
+                                        KErrDescrRegiontEmpty,
+                                        KScreenshotServiceUid );
+                        return;
+                        }
+
+                    TRect screenRect;
+                    screenRect.iBr = iScreenDevice->SizeInPixels().AsPoint();
+                    screenRect.iBr.iX++; //TRect::Contains() omitts
+                    screenRect.iBr.iY++; //right bottom rows
+
+                    TDisplayMode displayMode = ENone;
+                    if ( aMessage.Length() > KRegionDisplayOffset )
+                        {
+                        displayMode = ( TDisplayMode ) aMessage[KRegionDisplayOffset];
+                        if ( displayMode >= EColorLast )
+                            {
+                            iDispatcher->DispatchOutgoingErrorMessage(
+                                            KErrArgument,
+                                            KErrDescrInvalidMode,
+                                            KScreenshotServiceUid );
+                            return;
+                            }
+                        }
+
+                    if ( screenRect.Contains( region.iTl ) &&
+                         screenRect.Contains( region.iBr ) )
+                        {
+                        CreateBitmapL( region, displayMode );
+                        }
+                    else
+                        {
+                        iDispatcher->DispatchOutgoingErrorMessage(
+                                        KErrArgument,
+                                        KErrDescrRegionOutOfScreen,
+                                        KScreenshotServiceUid );
+                        return;
+                        }
+
+                    //check mime
+                    if ( aMessage.Length() > KRegionMIMEOffset )
+                        {
+                        mime.Set( aMessage.Mid( KRegionMIMEOffset ) );
+                        if ( !IsMIMETypeSupported( mime ) )
+                            {
+                            iDispatcher->DispatchOutgoingErrorMessage(
+                                            KErrArgument,
+                                            KErrDescrMIMENotSupported,
+                                            KScreenshotServiceUid );
+                            return;
+                            }
+                        }
+                    }
+                else
+                    {
+                    iDispatcher->DispatchOutgoingErrorMessage(
+                                    KErrArgument,
+                                    KErrDescrInvalid,
+                                    KScreenshotServiceUid );
+                    return;
+                    }
+                }
+                break;
+
+            case ECmdScreenSeries:
+            case ECmdScreenZipSeries:
+                {
+                if ( aMessage.Length() < KMinSeriesCmdLength )
+                    {
+                    iDispatcher->DispatchOutgoingErrorMessage(
+                                    KErrArgument,
+                                    KErrDescrInvalid,
+                                    KScreenshotServiceUid );
+                    return;
+                    }
+                TInt duration = ParseInt32( aMessage.Ptr() + KSeriesDurationOffset );
+                TInt interval = ParseInt32( aMessage.Ptr() + KSeriesIntervalOffset );
+
+                TDisplayMode displayMode = ( TDisplayMode ) aMessage[KSeriesDisplayOffset];
+                if ( displayMode >= EColorLast )
+                    {
+                    iDispatcher->DispatchOutgoingErrorMessage(
+                                    KErrArgument,
+                                    KErrDescrInvalidMode,
+                                    KScreenshotServiceUid );
+                    return;
+                    }
+
+                if ( aMessage.Length() > KSeriesMIMEOffset )
+                    {
+                    mime.Set( aMessage.Mid( KSeriesMIMEOffset ) );
+                    if ( !IsMIMETypeSupported( mime ) )
+                        {
+                        iDispatcher->DispatchOutgoingErrorMessage(
+                                        KErrArgument,
+                                        KErrDescrMIMENotSupported,
+                                        KScreenshotServiceUid );
+                        return;
+                        }
+                    }
+
+                TRect empty;
+                iSeriesShot->StartL( duration, interval, displayMode, empty, mime );
+                }
+                return;
+
+            case ECmdScreenRegionSeries:
+            case ECmdScreenRegionZipSeries:
+                {
+                if ( aMessage.Length() < KMinRegionSeriesCmdLength )
+                    {
+                    iDispatcher->DispatchOutgoingErrorMessage(
+                                    KErrArgument,
+                                    KErrDescrInvalid,
+                                    KScreenshotServiceUid);
+                    return;
+                    }
+                TInt duration = ParseInt32( aMessage.Ptr() + KSeriesDurationOffset );
+                TInt interval = ParseInt32( aMessage.Ptr() + KSeriesIntervalOffset );
+
+                TDisplayMode displayMode = ( TDisplayMode ) aMessage[KSeriesDisplayOffset];
+                if ( displayMode >= EColorLast )
+                    {
+                    iDispatcher->DispatchOutgoingErrorMessage(
+                                    KErrArgument,
+                                    KErrDescrInvalidMode,
+                                    KScreenshotServiceUid );
+                    return;
+                    }
+
+                TRect region;
+                const TUint8* ptr = aMessage.Ptr();
+                region.iTl.iX = ParseInt16( ptr + KRegionSeriesTlX );
+                region.iTl.iY = ParseInt16( ptr + KRegionSeriesTlY );
+                region.iBr.iX = ParseInt16( ptr + KRegionSeriesBlX );
+                region.iBr.iY = ParseInt16( ptr + KRegionSeriesBlY );
+
+                //check empty and normmalizaed
+                if ( !region.IsNormalized() )
+                    {
+                    iDispatcher->DispatchOutgoingErrorMessage(
+                                    KErrArgument,
+                                    KErrDescrRegionNotNormailized,
+                                    KScreenshotServiceUid );
+                    return;
+                    }
+
+                if ( region.IsEmpty() )
+                    {
+                    iDispatcher->DispatchOutgoingErrorMessage(
+                                    KErrArgument,
+                                    KErrDescrRegiontEmpty,
+                                    KScreenshotServiceUid );
+                    return;
+                    }
+
+                TRect screenRect;
+                screenRect.iBr = iScreenDevice->SizeInPixels().AsPoint();
+                screenRect.iBr.iX++; //TRect::Contains() omitts
+                screenRect.iBr.iY++; //right bottom rows
+
+                if ( !screenRect.Contains( region.iTl ) ||
+                     !screenRect.Contains( region.iBr ) )
+                    {
+                    iDispatcher->DispatchOutgoingErrorMessage(
+                                    KErrArgument,
+                                    KErrDescrRegionOutOfScreen,
+                                    KScreenshotServiceUid );
+                    return;
+                    }
+
+                if ( aMessage.Length() > KRegionSeriesMIMEOffset )
+                    {
+                    mime.Set( aMessage.Mid( KRegionSeriesMIMEOffset ) );
+                    if ( !IsMIMETypeSupported( mime ) )
+                        {
+                        iDispatcher->DispatchOutgoingErrorMessage(
+                                        KErrArgument,
+                                        KErrDescrMIMENotSupported,
+                                        KScreenshotServiceUid );
+                        return;
+                        }
+                    }
+
+                iSeriesShot->StartL( duration, interval, displayMode, region, mime );
+                }
+                return;
+
+            case ECmdSelectScreen:
+                {
+                if ( aMessage.Length() != KSelectScreenCmdLength )
+                    {
+                    iDispatcher->DispatchOutgoingErrorMessage(
+                                    KErrArgument,
+                                    KErrDescrInvalid,
+                                    KScreenshotServiceUid );
+                    return;
+                    }
+
+                TInt screenNr = aMessage[KScreenNrOffset];
+
+                TInt screens;
+                TInt ret=HAL::Get( HAL::EDisplayNumberOfScreens, screens );
+                if ( ret )
+                    {
+                    HTI_LOG_FORMAT( "HAL::Get failed %d", ret );
+                    User::Leave( ret );
+                    }
+
+
+                if ( ( screenNr > screens - 1 ) || ( screenNr < 0 ) )
+                    {
+                    iDispatcher->DispatchOutgoingErrorMessage(
+                                    KErrArgument,
+                                    KErrDescrScreenNotSupported,
+                                    KScreenshotServiceUid );
+                    return;
+                    }
+
+
+                HTI_LOG_FORMAT( "Number of screens %d", screens );
+                HTI_LOG_FORMAT( "Setting to screen index %d", screenNr );
+
+                // Clear the previous delta bitmap to avoid error
+                iPreviousBitmap->Reset();
+
+                // delete old screendevice and create a new one
+                delete iScreenDevice;
+                iScreenDevice = NULL;
+                iScreenDevice = new ( ELeave ) CWsScreenDevice( iWs );
+                User::LeaveIfError( iScreenDevice->Construct( screenNr ) );
+
+                TBuf8<1> okMsg;
+                okMsg.Append( ECmdSelectScreen );
+                iDispatcher->DispatchOutgoingMessage(
+                    okMsg.AllocL(), KScreenshotServiceUid );
+                }
+                return;
+
+            case ECmdDeltaScreenReset:
+                {
+                if ( aMessage.Length() != KDeltaResetCmdLength )
+                    {
+                    iDispatcher->DispatchOutgoingErrorMessage(
+                                    KErrArgument,
+                                    KErrDescrInvalid,
+                                    KScreenshotServiceUid );
+                    return;
+                    }
+
+                iPreviousBitmap->Reset();
+                TBuf8<1> okMsg;
+                okMsg.Append( ECmdDeltaScreenReset );
+                iDispatcher->DispatchOutgoingMessage(
+                    okMsg.AllocL(), KScreenshotServiceUid );
+                }
+                return;
+
+            case ECmdScreenMode:
+                {
+                if ( aMessage.Length() != KScreenModeCmdLength )
+                    {
+                    iDispatcher->DispatchOutgoingErrorMessage(
+                                    KErrArgument,
+                                    KErrDescrInvalid,
+                                    KScreenshotServiceUid );
+                    return;
+                    }
+
+                TInt focusScreen = iWs.GetFocusScreen();
+                TPixelsAndRotation sizeAndRotation;
+                TDisplayMode mode = ENone;
+                TInt thisScreen = iScreenDevice->GetScreenNumber();
+                iScreenDevice->GetDefaultScreenSizeAndRotation( sizeAndRotation );
+                mode = iScreenDevice->DisplayMode();
+
+                HTI_LOG_FORMAT( "This screen   = %d", thisScreen );
+                HTI_LOG_FORMAT( "Screen width  = %d", sizeAndRotation.iPixelSize.iWidth );
+                HTI_LOG_FORMAT( "Screen height = %d", sizeAndRotation.iPixelSize.iHeight );
+                HTI_LOG_FORMAT( "Rotation      = %d", sizeAndRotation.iRotation );
+                HTI_LOG_FORMAT( "Display mode  = %d", mode );
+                HTI_LOG_FORMAT( "Focus screen  = %d", focusScreen );
+                TBuf8<8> respMsg;
+                respMsg.Append( thisScreen );
+                respMsg.Append( ( TUint8* )( &( sizeAndRotation.iPixelSize.iWidth ) ), 2 );
+                respMsg.Append( ( TUint8* )( &( sizeAndRotation.iPixelSize.iHeight ) ), 2 );
+                respMsg.Append( sizeAndRotation.iRotation );
+                respMsg.Append( mode );
+                respMsg.Append( focusScreen );
+                iDispatcher->DispatchOutgoingMessage(
+                    respMsg.AllocL(), KScreenshotServiceUid );
+                }
+                return;
+
+            default:
+                //Error: unknown command
+                iDispatcher->DispatchOutgoingErrorMessage(
+                                KErrArgument,
+                                KErrDescrUnknownCommand,
+                                KScreenshotServiceUid );
+                return;
+            } // switch
+
+        //Encode iBitmap
+        if ( mime.Length() == 0 )
+            {
+            EncodeBitmapL(); //use default encoder BMP
+            }
+        else
+            {
+            HTI_LOG_DES( mime );
+            EncodeBitmapL( mime );
+            }
+        }
+    else
+        {
+        //error: empty request
+        iDispatcher->DispatchOutgoingErrorMessage(
+                        KErrArgument,
+                        KErrDescrUnknownCommand,
+                        KScreenshotServiceUid );
+        }
+
+    HTI_LOG_FUNC_OUT( "HtiScreenshotServicePlugin::ProcessMessage" );
+    }
+
+
+// ----------------------------------------------------------------------------
+void CHtiScreenshotServicePlugin::CreateBitmapL( TRect& aRegion,
+                                                 TDisplayMode aMode )
+    {
+    HTI_LOG_FUNC_IN( "CreateBitmapL" );
+    //create bitmap
+    TSize imageSize = aRegion.IsEmpty() ? iScreenDevice->SizeInPixels() :
+                        aRegion.Size();
+
+    TDisplayMode displayMode = aMode == ENone ?
+                                        iScreenDevice->DisplayMode() : aMode;
+
+    delete iScreen;//in case ICLComplete was not called
+    iScreen = NULL;
+    iScreen = new( ELeave ) CFbsBitmap;
+    User::LeaveIfError( iScreen->Create( imageSize, displayMode ) );
+
+    if ( aRegion.IsEmpty() )
+        {
+        iScreenDevice->CopyScreenToBitmap( iScreen );
+        }
+    else
+        {
+        iScreenDevice->CopyScreenToBitmap( iScreen, aRegion );
+        }
+
+
+    if ( iDeltaCapture )
+        {
+        HTI_LOG_TEXT( "DeltaCapture enabled" );
+
+
+        CFbsBitmap* differenceBitmap = NULL;
+        TInt err = ImageDifferenceL( iPreviousBitmap,
+                                     iScreen,
+                                     differenceBitmap,
+                                     iDeltaRect );
+
+        iPreviousBitmap->Reset();
+        iPreviousBitmap->Duplicate( iScreen->Handle() );
+
+        if ( err == KErrNone )
+            {
+            delete iScreen;
+            iScreen = differenceBitmap;
+            }
+        else if ( err == KErrNotFound )
+            {
+            delete iScreen;
+            iScreen = NULL;
+
+            if ( !iSeriesShot->IsOngoing() )
+                {
+                // Nothing has changed on the screen.
+                // Send just iDeltaRect coordidates
+                HBufC8* buf = HBufC8::NewL( 4 * 2 ); // 2 bytes for each coordinate
+                buf->Des().SetLength( 4 * 2 );
+                TUint16* ptr = (TUint16*) buf->Des().Ptr();
+                ptr[0] = (TUint16) iDeltaRect.iTl.iX;
+                ptr[1] = (TUint16) iDeltaRect.iTl.iY;
+                ptr[2] = (TUint16) iDeltaRect.iBr.iX;
+                ptr[3] = (TUint16) iDeltaRect.iBr.iY;
+                // Response also sent in ICLComplete
+                iDispatcher->DispatchOutgoingMessage( buf, KScreenshotServiceUid );
+                }
+            }
+        }
+
+    HTI_LOG_FUNC_OUT( "CreateBitmapL" );
+    }
+/*
+
+// ----------------------------------------------------------------------------
+void CleanupRArray( TAny* object )
+    {
+    ((RImageTypeDescriptionArray*)object)->ResetAndDestroy();
+    }
+
+// ----------------------------------------------------------------------------
+void CHtiScreenshotServicePlugin::SelectEncoder( const TUid aEncoderUid )
+    {
+    //select encoder
+    RImageTypeDescriptionArray imageTypeArray;
+    CImageEncoder::GetImageTypesL( imageTypeArray );
+    CleanupStack::PushL( TCleanupItem(CleanupRArray, &imageTypeArray) );
+
+    //select specified encoder
+    TBool found = EFalse;
+    for ( TInt i = 0; i < imageTypeArray.Count(); ++i )
+        {
+        if ( imageTypeArray[i]->ImageType() == aEncoderUid )
+            {
+            iImageEncoderType = imageTypeArray[i]->ImageType();
+            iImageEncoderSubtype = imageTypeArray[i]->SubType();
+            found = ETrue;
+            }
+        }
+
+    if ( !found )
+        {
+        User::Leave( KErrNotFound );
+        }
+    CleanupStack::PopAndDestroy(); //imageTypeArray
+    }
+*/
+
+// ----------------------------------------------------------------------------
+TBool CHtiScreenshotServicePlugin::IsMIMETypeSupported(TDesC8 &aMime)
+    {
+    HTI_LOG_DES(aMime);
+    RFileExtensionMIMETypeArray array;
+    CImageEncoder::GetFileTypesL(array);
+    for ( TInt i = 0; i < array.Count(); i++ )
+        {
+        if ( array[i]->MIMEType() == aMime )
+            {
+            HTI_LOG_TEXT( "MIME supported" );
+            array.ResetAndDestroy();
+            return ETrue;
+            }
+        }
+    HTI_LOG_TEXT( "MIME not supported" );
+    array.ResetAndDestroy();
+    return EFalse;
+    }
+
+
+// ----------------------------------------------------------------------------
+void CHtiScreenshotServicePlugin::EncodeBitmapL(const TDesC8& aImageTypeMIME )
+    {
+    HTI_LOG_FUNC_IN( "EncodeBitmapL" );
+    delete iBitmapEncoder;
+    iBitmapEncoder = NULL;
+    delete iICLHandler;
+    iICLHandler = NULL;
+
+    if ( iScreen )
+        {
+        HTI_LOG_TEXT( "create encoder" );
+        if ( aImageTypeMIME  == KNullDesC8 )
+            {
+            iBitmapEncoder = CImageEncoder::DataNewL( iEncodedBitmap,
+                                        CImageEncoder::EOptionNone,
+                                        KImageTypeBMPUid);//,
+                                        //iImageEncoderSubtype);
+            }
+        else
+            {
+            iBitmapEncoder = CImageEncoder::DataNewL( iEncodedBitmap,
+                                        aImageTypeMIME);
+            }
+
+        HTI_LOG_TEXT( "create CICLHandler" );
+        iICLHandler = new(ELeave) CICLHandler( iBitmapEncoder, this );
+        iBitmapEncoder->Convert( &(iICLHandler->iStatus), *iScreen );
+
+        HTI_LOG_TEXT( "CICLHandler start");
+        iICLHandler->Start();
+        }
+    else
+        {
+        HTI_LOG_TEXT( "Nothing to encode" );
+        }
+
+    HTI_LOG_FUNC_OUT( "EncodeBitmapL" );
+    }
+
+// ----------------------------------------------------------------------------
+TInt CHtiScreenshotServicePlugin::Compress()
+    {
+    __ASSERT_ALWAYS(iEncodedBitmap!=NULL,User::Panic(KScreenshotPanic, KErrGeneral));
+    TInt err = KErrNone;
+    HBufC8* zippedTemp = NULL;
+
+    HTI_LOG_FORMAT( "image size %d", iEncodedBitmap->Size() );
+    TInt numOfSteps = 4;
+    TInt comprBufferIncrease = iEncodedBitmap->Size()/numOfSteps;
+
+    //straight way to handle cases
+    //when compressed data larger than uncompressed
+    //try until buffer for compr. data twice bigger than original data
+    for ( TInt i = 0; i < numOfSteps; ++i )
+        {
+        delete zippedTemp;
+        TRAP( err, zippedTemp = HBufC8::NewL( iEncodedBitmap->Size() +
+                                              i*comprBufferIncrease ) );
+        if ( err == KErrNone )
+            {
+            //try to zip
+            HTI_LOG_TEXT( "try to zip" );
+            TPtr8 zippedTempPtr = zippedTemp->Des();
+            TRAP( err, CEZCompressor::CompressL( zippedTempPtr,
+                                                 *iEncodedBitmap ) );
+            if ( err == KErrNone || err != KEZlibErrBuf )
+                {
+                break;
+                }
+            }
+        else
+            {
+            break;
+            }
+        }
+
+    if ( err == KErrNone )
+        {
+        delete iEncodedBitmap;
+        iEncodedBitmap = zippedTemp;
+        }
+    else
+        {
+        HTI_LOG_FORMAT( "compre error %d", err );
+        delete zippedTemp;
+        }
+
+    return err;
+    }
+
+// ----------------------------------------------------------------------------
+void CHtiScreenshotServicePlugin::ICLComplete( TInt anError)
+    {
+    HTI_LOG_FUNC_IN( "ICLComplete" );
+
+    //delete what we dont need right away
+    delete iBitmapEncoder;
+    iBitmapEncoder = NULL;
+    delete iICLHandler;
+    iICLHandler = NULL;
+
+
+    if ( anError==KErrNone )
+        {
+        TInt err = KErrNone;
+
+
+        //compress
+        if ( iCompress )
+            {
+            HTI_LOG_TEXT( "compress" );
+            err = Compress();
+            }
+
+        //send
+        if ( err == KErrNone )
+            {
+
+            if ( !iSeriesShot->IsOngoing() )
+                {
+                // Not a series shot
+
+                if ( iDeltaCapture )
+                    {
+                    // DeltaCapture on
+
+                    // If we have encoded the bitmap then we
+                    // also have some difference in the bitmap
+
+                    HTI_LOG_TEXT( "Sending image with coordinates..." );
+
+                    HBufC8* buf = HBufC8::NewL( (4*2) + iEncodedBitmap->Size() );
+                    buf->Des().SetLength(4*2);
+                    TUint16* ptr = (TUint16*) buf->Des().Ptr();
+                    ptr[0] = (TUint16) iDeltaRect.iTl.iX;
+                    ptr[1] = (TUint16) iDeltaRect.iTl.iY;
+                    ptr[2] = (TUint16) iDeltaRect.iBr.iX;
+                    ptr[3] = (TUint16) iDeltaRect.iBr.iY;
+
+                    buf->Des().Append(*iEncodedBitmap);
+
+                    delete iEncodedBitmap;
+                    iEncodedBitmap = NULL;
+
+                    // Response also sent in CreateBitmapL
+                    err = iDispatcher->DispatchOutgoingMessage(buf,
+                                            KScreenshotServiceUid);
+                    }
+                else
+                    {
+                    // Normal case
+                    HTI_LOG_TEXT( "Sending image..." );
+                    err = iDispatcher->DispatchOutgoingMessage(iEncodedBitmap,
+                                            KScreenshotServiceUid);
+                    }
+
+                if (  err == KErrNoMemory )
+                    {
+                    HTI_LOG_TEXT( "wait for memory" );
+                    iDispatcher->AddMemoryObserver( this );
+                    }
+                else if ( err == KErrNone )
+                    {
+                    iEncodedBitmap = NULL;
+                    }
+                else //just drop
+                    {
+                    HTI_LOG_TEXT( "ERROR: Impossible to send image" );
+                    delete iEncodedBitmap;
+                    iEncodedBitmap = NULL;
+                    }
+                }
+            }
+        else
+            {
+            iSeriesShot->Cancel();
+            iDispatcher->DispatchOutgoingErrorMessage(
+                    err,
+                    KErrDescrFailedCompress,
+                    KScreenshotServiceUid);
+            delete iEncodedBitmap;
+            iEncodedBitmap = NULL;
+            }
+        }
+    else
+        {
+        iSeriesShot->Cancel();
+        iDispatcher->DispatchOutgoingErrorMessage(
+                        anError,
+                        KErrDescrFailedConvert,
+                        KScreenshotServiceUid);
+        delete iEncodedBitmap;
+        iEncodedBitmap = NULL;
+        }
+
+    if ( iSeriesShot->IsOngoing() )
+        {
+        iSeriesShot->SaveImage( iEncodedBitmap, iCompress );
+        delete iEncodedBitmap;
+        iEncodedBitmap = NULL;
+
+        // Check if there's still more to do
+        if ( iSeriesShot->IsOngoing() )
+            {
+            iSeriesShot->TriggerNewShot();
+            }
+        else
+            {
+            // - No, timer still active
+            // SeriesShot can complete here and in CSeriesShot::TimerExpired
+            SeriesShotCompletedL(iSeriesShot->ConstructCompletedMessageL());
+            }
+        }
+
+    HTI_LOG_FUNC_OUT( "ICLComplete" );
+    }
+
+// ----------------------------------------------------------------------------
+void CHtiScreenshotServicePlugin::NotifyMemoryChange( TInt aAvailableMemory )
+    {
+    if ( iEncodedBitmap )
+        {
+        if ( aAvailableMemory>= iEncodedBitmap->Size() )
+            {
+            TInt err = iDispatcher->DispatchOutgoingMessage(iEncodedBitmap,
+                                KScreenshotServiceUid);
+
+            if ( err == KErrNone)
+                {
+                iEncodedBitmap = NULL;
+                iDispatcher->RemoveMemoryObserver( this );
+                }
+            else if ( err != KErrNoMemory )
+                {
+                delete iEncodedBitmap;
+                iEncodedBitmap = NULL;
+                iDispatcher->RemoveMemoryObserver( this );
+                }
+            }
+        }
+    else
+        {
+        //some error, should not be called
+        iDispatcher->RemoveMemoryObserver(this);
+        }
+    }
+
+// ----------------------------------------------------------------------------
+void CHtiScreenshotServicePlugin::SeriesShotCompletedL(HBufC8* aMsg)
+    {
+    HTI_LOG_FUNC_IN( "CHtiScreenshotServicePlugin::SeriesShotCompletedL" );
+    User::LeaveIfError( iDispatcher->DispatchOutgoingMessage(
+                        aMsg,
+                        KScreenshotServiceUid) );
+    HTI_LOG_FUNC_OUT( "CHtiScreenshotServicePlugin::SeriesShotCompletedL" );
+    }
+
+// ----------------------------------------------------------------------------
+TBool CHtiScreenshotServicePlugin::StartShotL(TRect aRegion, TDisplayMode aDisplayMode, TDesC8 &aMimeType)
+    {
+    HTI_LOG_FUNC_IN( "CHtiScreenshotServicePlugin::StartShot" );
+    CreateBitmapL( aRegion, aDisplayMode );
+
+    if ( aMimeType.Length()==0 )
+        EncodeBitmapL(); //use default encoder BMP
+    else
+        EncodeBitmapL( aMimeType );
+
+    HTI_LOG_FUNC_OUT( "CHtiScreenshotServicePlugin::StartShot" );
+    return iScreen ? ETrue : EFalse;
+    }
+
+// ----------------------------------------------------------------------------
+CSeriesShot* CSeriesShot::NewL( MSeriesShotObserver* aServicePlugin )
+    {
+    HTI_LOG_FUNC_IN( "CSeriesShot::NewL" );
+    CSeriesShot* self = new (ELeave) CSeriesShot( aServicePlugin );
+    CleanupStack::PushL (self);
+    self->ConstructL();
+    CleanupStack::Pop();
+    HTI_LOG_FUNC_OUT( "CSeriesShot::NewL" );
+    return self;
+    }
+
+// ----------------------------------------------------------------------------
+void CSeriesShot::ConstructL()
+    {
+    User::LeaveIfError(iFs.Connect());
+    }
+
+// ----------------------------------------------------------------------------
+CSeriesShot::CSeriesShot( MSeriesShotObserver* aServicePluginObserver ):
+    iServicePluginObserver( aServicePluginObserver ),
+    iDurationTimer( NULL ),
+    iIntervalTimer( NULL ),
+    isEncoding( EFalse )
+    {
+    }
+
+// ----------------------------------------------------------------------------
+CSeriesShot::~CSeriesShot()
+    {
+    Cancel();
+    iFs.Close();
+    }
+
+// ----------------------------------------------------------------------------
+void CSeriesShot::ClearShots()
+    {
+    HTI_LOG_FUNC_IN( "CSeriesShot::ClearShots" );
+
+    iFs.MkDirAll( KSeriesShotPath );
+
+    // Delete all files
+    TFileName files;
+    files.Append( KSeriesShotPath );
+    files.Append( _L( "*.*" ) );
+    HTI_LOG_DES(files);
+
+
+    CFileMan *fileman = CFileMan::NewL( iFs );
+    TInt err = fileman->Delete( files );
+    HTI_LOG_FORMAT( "delete %d", err );
+    if ( err != KErrNotFound )
+        User::LeaveIfError( err );
+    delete fileman;
+
+
+    HTI_LOG_FUNC_OUT( "CSeriesShot::ClearShots" );
+    }
+
+// ----------------------------------------------------------------------------
+void CSeriesShot::StartL( TTimeIntervalMicroSeconds32 aDuration,
+                         TTimeIntervalMicroSeconds32 aInterval,
+                         TDisplayMode aDisplayMode,
+                         TRect aRegion,
+                         TPtrC8 aMime )
+    {
+    HTI_LOG_FUNC_IN( "CSeriesShot::StartL" );
+    HTI_LOG_FORMAT( "Duration      : %d microseconds", aDuration.Int() );
+    HTI_LOG_FORMAT( "Interval      : %d microseconds", aInterval.Int() );
+    HTI_LOG_FORMAT( "Displaymode   : %d", aDisplayMode );
+    HTI_LOG_FORMAT( "TopLeft X     : %d", aRegion.iTl.iX );
+    HTI_LOG_FORMAT( "TopLeft Y     : %d", aRegion.iTl.iY );
+    HTI_LOG_FORMAT( "BottomRight X : %d", aRegion.iBr.iX );
+    HTI_LOG_FORMAT( "BottomRight Y : %d", aRegion.iBr.iY );
+
+    iDisplayMode = aDisplayMode;
+    iRegion = aRegion;
+    iIndex = 0;
+
+    iMimeType.Zero();
+    iMimeType.Append( aMime );
+    HTI_LOG_DES( iMimeType );
+
+#ifdef __ENABLE_LOGGING__
+    HTI_LOG_TEXT( "Supported MIME types:" );
+    RFileExtensionMIMETypeArray array;
+    CImageEncoder::GetFileTypesL( array );
+    for ( TInt i = 0; i < array.Count(); i++ )
+        HTI_LOG_DES( array[i]->MIMEType() );
+    array.ResetAndDestroy();
+#endif
+
+    iExtension.Zero();
+    if ( iMimeType.Length() == 0 )
+        iExtension.Append( _L( ".bmp" ) );
+    else
+        GetMIMEExtension( iMimeType, iExtension );
+
+    ClearShots();
+
+    iDurationTimer = CSeriesShotTimer::NewL( this, EDuration, aDuration );
+    iIntervalTimer = CSeriesShotTimer::NewL( this, EInterval, aInterval );
+    iDurationTimer->Start();
+    TimerExpired( EInterval ); // trigger first shot immidietly
+
+    HTI_LOG_FUNC_OUT( "CSeriesShot::StartL" );
+    }
+
+void CSeriesShot::TimerExpired( TInt aId )
+    {
+    HTI_LOG_FUNC_IN( "CSeriesShot::TimerExpired" );
+    switch ( aId )
+        {
+        case EDuration:
+            HTI_LOG_TEXT( "EDuration" );
+
+            delete iDurationTimer;
+            iDurationTimer = NULL;
+
+            if ( iIntervalTimer ) // I'm paranoid
+                {
+                delete iIntervalTimer;
+                iIntervalTimer = NULL;
+                }
+            // SeriesShot can complete here and in CHtiScreenshotServicePlugin::ICLComplete
+            if ( isEncoding == EFalse )
+                iServicePluginObserver->SeriesShotCompletedL( ConstructCompletedMessageL() );
+
+            break;
+
+        case EInterval:
+            HTI_LOG_TEXT( "EInterval" );
+
+            isEncoding = iServicePluginObserver->StartShotL( iRegion, iDisplayMode, iMimeType );
+
+            break;
+
+        default:
+            break;
+        }
+    HTI_LOG_FUNC_OUT( "CSeriesShot::TimerExpired" );
+    }
+
+// ----------------------------------------------------------------------------
+TBool CSeriesShot::IsOngoing()
+    {
+    // It still might be encoding when duration timer has expired
+    return ( iDurationTimer || isEncoding ) ? ETrue : EFalse;
+    }
+
+// ----------------------------------------------------------------------------
+void CSeriesShot::SaveImage( TDesC8* aImage, TBool isCompressed )
+    {
+    HTI_LOG_FUNC_IN( "CSeriesShot::SaveImage" );
+
+    isEncoding = EFalse;
+
+    TFileName filename( KSeriesShotPath );
+    filename.AppendFormat( _L( "%04d" ), iIndex );
+    iIndex++;
+    filename.Append( iExtension );
+    if ( isCompressed )
+        filename.Append( _L( "z" ) );
+    HTI_LOG_DES( filename );
+
+    RFile file;
+    User::LeaveIfError( file.Create( iFs, filename, EFileWrite ) );
+    User::LeaveIfError( file.Write( *aImage ) );
+    file.Close();
+
+    HTI_LOG_FUNC_IN( "CSeriesShot::SaveImage" );
+    }
+
+// ----------------------------------------------------------------------------
+void CSeriesShot::TriggerNewShot()
+    {
+    if ( iDurationTimer )
+        iIntervalTimer->Start();
+    }
+
+// ----------------------------------------------------------------------------
+void CSeriesShot::Cancel()
+    {
+    if ( iDurationTimer )
+        {
+        delete iDurationTimer;
+        iDurationTimer = NULL;
+        }
+    if ( iIntervalTimer )
+        {
+        delete iIntervalTimer;
+        iIntervalTimer = NULL;
+        }
+    ClearShots();
+    }
+
+// ----------------------------------------------------------------------------
+void CSeriesShot::EncodeCompleted()
+    {
+    isEncoding = EFalse;
+    }
+
+// ----------------------------------------------------------------------------
+void CSeriesShot::GetMIMEExtension( TDesC8 &aMime, TDes &aExt )
+    {
+    RFileExtensionMIMETypeArray array;
+    CImageEncoder::GetFileTypesL( array );
+    for ( TInt i = 0; i < array.Count(); i++ )
+        {
+        if ( array[i]->MIMEType() == aMime )
+            aExt.Append( array[i]->FileExtension() );
+        }
+    array.ResetAndDestroy();
+
+    if ( aExt == KNullDesC ) // should not happen
+        aExt.Append( _L( ".xxx" ) );
+    }
+
+// ----------------------------------------------------------------------------
+HBufC8* CSeriesShot::ConstructCompletedMessageL()
+    {
+    HTI_LOG_FUNC_IN( "CSeriesShot::ConstructCompletedMessageL" );
+    // Serialshot completed send ok message.
+
+    CDir* dir = NULL;
+    User::LeaveIfError( iFs.GetDir(
+        KSeriesShotPath, KEntryAttNormal, ESortByName, dir ) );
+
+    TInt msgSize = 0;
+
+    if ( dir->Count() == 0 )
+        {
+        HTI_LOG_TEXT( "No shots found! Leaving..." );
+        User::Leave( KErrNotFound );
+        }
+
+    for ( TInt i = 0; i < dir->Count(); i++ )
+        {
+        msgSize += 1; // for length field
+        msgSize += KSeriesShotPath().Length();
+        msgSize += (*dir)[i].iName.Length();
+        }
+
+    HBufC8* msg = HBufC8::NewL( msgSize );
+
+    for ( TInt i = 0; i < dir->Count(); i++ )
+        {
+        msg->Des().Append( KSeriesShotPath().Length() + (*dir)[i].iName.Length() );
+        msg->Des().Append( KSeriesShotPath );
+        msg->Des().Append( (*dir)[i].iName );
+        }
+
+    delete dir;
+
+    HTI_LOG_FUNC_OUT( "CSeriesShot::ConstructCompletedMessageL" );
+    return msg;
+    }
+
+// ----------------------------------------------------------------------------
+CSeriesShotTimer* CSeriesShotTimer::NewL( MSeriesShotTimerObserver* aObserver,
+                                        TInt aId,
+                                        TTimeIntervalMicroSeconds32 aTime )
+    {
+    HTI_LOG_FUNC_IN( "CSeriesShotTimer::NewL" );
+    CSeriesShotTimer* self = new (ELeave) CSeriesShotTimer( aObserver, aId, aTime );
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    CleanupStack::Pop();
+    HTI_LOG_FUNC_OUT( "CSeriesShotTimer::NewL" );
+    return self;
+    }
+
+// ----------------------------------------------------------------------------
+void CSeriesShotTimer::ConstructL()
+    {
+    HTI_LOG_FUNC_IN( "CSeriesShotTimer::ConstructL" );
+    CTimer::ConstructL();
+    if ( !IsAdded() ) // CTimer should add it but it seems that it does NOT!
+        {
+        CActiveScheduler::Add( this );
+        }
+    HTI_LOG_FUNC_OUT( "CSeriesShotTimer::ConstructL" );
+    }
+
+// ----------------------------------------------------------------------------
+CSeriesShotTimer::CSeriesShotTimer( MSeriesShotTimerObserver* aObserver,
+                                  TInt aId,
+                                  TTimeIntervalMicroSeconds32 aTime ):
+    CTimer( EPriorityStandard ),
+    iObserver( aObserver ),
+    iId( aId ),
+    iTime( aTime )
+    {
+    }
+
+// ----------------------------------------------------------------------------
+CSeriesShotTimer::~CSeriesShotTimer()
+    {
+    }
+
+// ----------------------------------------------------------------------------
+void CSeriesShotTimer::RunL()
+    {
+    iObserver->TimerExpired( iId );
+    }
+
+// ----------------------------------------------------------------------------
+void CSeriesShotTimer::Start()
+    {
+    HTI_LOG_FORMAT( "Start CSeriesShotTimer : %d microseconds", iTime.Int() );
+    After( iTime );
+    }