uiacceltk/hitchcock/coretoolkit/src/HuiRasterizedTextMesh.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 02 Feb 2010 07:56:43 +0200
changeset 0 15bf7259bb7c
permissions -rw-r--r--
Revision: 201003

/*
* Copyright (c) 2006-2007 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:   Implementation of CHuiRasterizedTextMesh. CHuiRasterizedTextMesh 
*                stores a rasterized bitmap version of a text string.
*
*/


#include <s32mem.h>
#include "HuiRasterizedTextMesh.h"
#include "HuiRenderPlugin.h"
#include "uiacceltk/HuiEnv.h"
#include "uiacceltk/HuiSkin.h"
#include "uiacceltk/HuiStatic.h"
#include "uiacceltk/HuiFont.h"
#include "uiacceltk/HuiTexture.h"
#include "uiacceltk/HuiGc.h"
#include "uiacceltk/HuiUtil.h"
#include "uiacceltk/HuiPanic.h"

#include "uiacceltk/huitextstylemanager.h" // @todo remove when text drawing is moved to THuiFont
#include "uiacceltk/huitextstyle.h" // @todo remove when text drawing is moved to THuiFont
#include "uiacceltk/huidropshadow.h"
#include "uiacceltk/HuiTextureProcessor.h"

#include <AknBidiTextUtils.h>
#include <AknPictographInterface.h>
#include <AknPictographDrawerInterface.h>


/** Granularity of line wrapping array. */
const TInt KLineArrayGranularity = 4;

enum THuiRasterizeLevel
    {
    ERasterizeNone = 0x0,
    ERasterizeText = 0x1,           
    ERasterizePictographs = 0x2,           
    ERasterizeAll = 0xFFFFFFFF
    };

EXPORT_C CHuiRasterizedTextMesh* CHuiRasterizedTextMesh::NewL()
    {
    CHuiRasterizedTextMesh* self = CHuiRasterizedTextMesh::NewLC();
    CleanupStack::Pop(self);
    return self;
    }


CHuiRasterizedTextMesh* CHuiRasterizedTextMesh::NewLC()
    {
    CHuiRasterizedTextMesh* self = new (ELeave) CHuiRasterizedTextMesh();
    CleanupStack::PushL(self);
    self->ConstructL();
    return self;
    }


CHuiRasterizedTextMesh::CHuiRasterizedTextMesh()
    {
    }

CHuiRasterizedTextMesh::~CHuiRasterizedTextMesh()
    {
    ResetLines();
    iLines.Close();
    ResetPictographLines();
    iPictographLines.Close();
    delete iPictographBitmap;
    }


void CHuiRasterizedTextMesh::Reset()
    {
    if (!iUsingPreRasterizedMesh)
        {
        CHuiTextMesh::Reset();
        ResetLines();
        ResetPictographLines();
        }
    }

void CHuiRasterizedTextMesh::ResetLines()
    {
    HUI_DEBUG(_L("CHuiRasterizedTextMesh::ResetLines() - Deleting textures for all rasterized lines."));

    for(TInt i = 0; i < iLines.Count(); ++i)
        {
        if (!iUsingPreRasterizedMesh) 
            {
            delete iLines[i].iTexture;
            }
        iLines[i].iTexture = NULL;
        }

    iLines.Reset();
    }

void CHuiRasterizedTextMesh::ResetPictographLines()
    {
    HUI_DEBUG(_L("CHuiRasterizedTextMesh::ResetPictographLines() - Deleting textures for all rasterized lines."));

    for(TInt i = 0; i < iPictographLines.Count(); ++i)
        {
        delete iPictographLines[i].iTexture; iPictographLines[i].iTexture = NULL;
        }

    iPictographLines.Reset();
    }


TBool CHuiRasterizedTextMesh::IsMaxLineCountReached() const
    {
    return iLines.Count() >= MaxLineCount();
    }


TBool CHuiRasterizedTextMesh::RasterizeLineL(const TDesC& aTextLine, SRasterizedLine & aLineOut)
    {
    if(iUsingPreRasterizedMesh)
        {
        return ETrue;
        }
    // Retrieve the used text style.
    THuiTextStyle* textStyle = CHuiStatic::Env().TextStyleManager().TextStyle(iTextStyleId);
    
    // Calculate line extents and assign it to texture size.
    TSize textureSize = textStyle->LineExtentsL(aTextLine);
    
    if(textureSize.iWidth == 0)
        {
        // This is an empty string. We will not rasterize it.
        // Just add a gap.
        aLineOut.iTexture = NULL;
        aLineOut.iGap = textureSize.iHeight; // @todo: refacture/rename iGap? iGap is used as a size of an empty line?

        HUI_DEBUG1(_L("CHuiRasterizedTextMesh::RasterizeLineL() - Added line gap: %i"),
                   aLineOut.iGap);

        return !IsMaxLineCountReached();
        }

    // Create a texture for storing the text into.
    if (aLineOut.iTexture == NULL)
        {
        HUI_DEBUG1(_L("CHuiRasterizedTextMesh::RasterizeLineL() - Registering self (0x%x) as a texture content observer."), this);
        aLineOut.iTexture = CHuiTexture::NewL();
        // Register one content observer for the first texture that
        // is able to restore all lines in a single run
        if (iLines.Count()==1)
            {
            aLineOut.iTexture->iContentObservers.AppendL(*this);
            }
        aLineOut.iGap = 0;
        }

    // set a name for the texture
    aLineOut.iTexture->SetImageFileNameL(aTextLine);
    
    // Rasterize string using the defined text style.
    textStyle->RasterizeLineL(aTextLine, *aLineOut.iTexture);

    if ( RasterizedShadow() && aLineOut.iTexture )
        {
        const TInt requestedBlurredSize = HUI_ROUND_FLOAT_TO_INT( 2*iVisual->DropShadowHandler()->iRadius.Now() );
        aLineOut.iTexture->CreateShadowTextureL( requestedBlurredSize, EHuiTextureShadowStyleRasterizedText );
        }


    return !IsMaxLineCountReached();
    }

TBool CHuiRasterizedTextMesh::RasterizePictographLineL(const TDesC& aTextLine, CFont* aFont, SRasterizedLine & aLineOut)
    {
    if(iUsingPreRasterizedMesh)
        {
        return EFalse;
        }

    // Retrieve the used text style.
    THuiTextStyle* textStyle = CHuiStatic::Env().TextStyleManager().TextStyle(iTextStyleId);
    
    // Calculate line extents and assign it to texture size.
    TSize textureSize = textStyle->LineExtentsL(aTextLine);
	    
    if(textureSize.iWidth == 0 || !iPictographInterface || !iPictographInterface->Interface()->ContainsPictographs(aTextLine))
        {
        // This is an empty string or it does not contain pictographs. We will not rasterize it.
        // Just add a gap.
        aLineOut.iTexture = NULL;
        aLineOut.iGap = textureSize.iHeight;
        return !IsMaxLineCountReached(); 
        }

    // store the actual size to be assigned as the textures logical size
    TSize actualsize(textureSize);

    if (aLineOut.iTexture == NULL)
        {
    // Create a texture for storing the pictographs into.
        aLineOut.iTexture = CHuiTexture::NewL();
        HUI_DEBUG1(_L("CHuiRasterizedTextMesh::RasterizePictographLineL() - Registering self (0x%x) as a texture content observer."), this);        
        // Register one content observer for the first texture that
        // is able to restore all lines in a single run
        if (iLines.Count()==1)
            {
            aLineOut.iTexture->iContentObservers.AppendL(*this);
            }
        aLineOut.iGap = 0;
        }

    // set a name for the texture
    // @todo is this needed, what names to use
    aLineOut.iTexture->SetImageFileNameL(_L("Pictographs"));

    TSize maxTextureSize = aLineOut.iTexture->MaxTextureSize();
    textureSize.iWidth = Min(textureSize.iWidth, maxTextureSize.iWidth);
    textureSize.iHeight = Min(textureSize.iHeight, maxTextureSize.iHeight);

    if((textureSize.iWidth == 0) || (textureSize.iHeight == 0))
        {
        // Cannot draw into this tiny texture, so leave.
        HUI_DEBUG2(_L("CHuiRasterizedTextMesh::RasterizePictographLineL() - texture size was too small to draw into (%i, %i)."), textureSize.iWidth, textureSize.iHeight);
        User::Leave(KErrAbort);
        }

    User::LeaveIfError( iPictographBitmap->Resize(textureSize) );

    CFbsBitmapDevice* device = CFbsBitmapDevice::NewL(iPictographBitmap);
    CleanupStack::PushL(device);

    CFbsBitGc* gc = 0;
    User::LeaveIfError( device->CreateContext(gc) );
    CleanupStack::PushL(gc);

    // Prepare the bitmap for drawing...set drawmode because of EColor16MA mode...
    gc->SetDrawMode(CGraphicsContext::EDrawModeWriteAlpha); 

    TRgb color = KRgbWhite;
    color.SetAlpha(0x00);
    gc->SetBrushColor(color);
    gc->Clear();
    gc->UseFont(aFont);  
    
	// Draw pictorgraphs
    iPictographInterface->Interface()->DrawPictographsInText(
            *gc,
            *aFont,
            aTextLine, TPoint(0, aFont->FontMaxAscent()));

    CleanupStack::PopAndDestroy(gc);
    CleanupStack::PopAndDestroy(device);

    aLineOut.iTexture->UploadL(*iPictographBitmap, NULL, EHuiTextureUploadFlagRetainResolution);
    aLineOut.iTexture->SetSize(actualsize);
    return !IsMaxLineCountReached();
    }

void CHuiRasterizedTextMesh::BuildL(TBool aRasterize)
    {
    if (aRasterize)
        {
        DoBuildL(ERasterizeAll);    
        }
    else
        {
        DoBuildL(ERasterizeNone);                
        }    
    }

void CHuiRasterizedTextMesh::DoBuildL(TInt aRasterizeFlags)
    {
    if(iUsingPreRasterizedMesh)
        {
        return;
        }

    TSize extents(0, 0);
    
    HUI_DEBUG(_L("CHuiRasterizedTextMesh::BuildL() - Updating rasterized text."));

    // This is never NULL during BuildL().
    const TDesC& text = *Text();
    
    // Retrieve the text style used when rasterizing this text mesh.
    THuiTextStyle* textStyle = CHuiStatic::Env().TextStyleManager().TextStyle(iTextStyleId);

    // Retrieve the CFont object used when rasterizing this text mesh.
    CFont* font = textStyle->Font().NearestFontL(iTextMeshScale);

    // Maximum width of a text line in pixels.
    TInt maxWidth = MaxLineWidth();

    TInt startIndex = 0;
    TInt index = 0;
    TInt lineCount = 0;

    CArrayFixFlat<TPtrC>* linePtrs = new (ELeave) CArrayFixFlat<TPtrC>(KLineArrayGranularity);
    CleanupStack::PushL(linePtrs);

    while(startIndex < text.Length())
        {
        /// @todo What is the Symbian way to determine line break chars?
#define HUI_IS_LINE_BREAK(aChar) (aChar == '\n')

        // Find the next logical line.
        while(index < text.Length() && !HUI_IS_LINE_BREAK(text[index]))
            {
            index++;
            }

        TPtrC logicalLine = text.Mid(startIndex, index - startIndex);
        ++index; // Skip the line break.
        startIndex = index;

        switch(LineMode())
            {
            case ELineModeTruncate:
                {
                ++lineCount; // there's always one line created per logical line
                HBufC* buf = logicalLine.AllocLC();
                TPtr ptr = buf->Des();
                // truncate line
                CHuiStatic::ConvertToVisualAndClipL(ptr, *font, maxWidth, maxWidth);
                // create the line entry if not already existing
                
                if (aRasterizeFlags != ERasterizeNone)
                	{
                    if (iLines.Count() < lineCount)
                        {
                        SRasterizedLine line;
                        line.iTexture = NULL;
                        line.iGap = 0;
                        iLines.AppendL(line);
                        
                        if (iPictographInterface)
                            {
                            SRasterizedLine pictographline;
                            pictographline.iTexture = NULL;
                            pictographline.iGap = 0;
                            iPictographLines.AppendL(pictographline);                                
                            }
                        }                	
                        
                	TInt currentLine = lineCount-1;
    	            if (aRasterizeFlags & ERasterizeText)
    	                {
    	                // rasterize a single line (updates texture in iLines[0].iTexture)
        	            RasterizeLineL(ptr, iLines[currentLine]);	                    
    	                }

    	            if (aRasterizeFlags & ERasterizePictographs && iPictographInterface)
    	                {
                        // Rasterize pictographs if needed
        	            RasterizePictographLineL(ptr, font, iPictographLines[currentLine]);
    	                }

    	            // Get extents from the texture we just created
                    CHuiTexture* tex = iLines[currentLine].iTexture;
                    extents.iHeight += iLines[currentLine].iGap;
                    if(tex)
                        {
                        extents.iWidth = Max(extents.iWidth, tex->Size().iWidth);
                        extents.iHeight += tex->Size().iHeight;
                        }	                
                	}
                else
                    {
                    // Don't rasterise or create textures, just get the extents of this text.
                    TSize lineExtents = textStyle->LineExtentsL(ptr);
                    extents.iWidth = Max(extents.iWidth, lineExtents.iWidth);
                    extents.iHeight += lineExtents.iHeight;                    
                    }

                	
        	    CleanupStack::PopAndDestroy(buf);
                break;
                }

            case ELineModeWrap:
                {
                // wrap lines to array
                HBufC* buf = CHuiStatic::ConvertToVisualAndWrapToArrayL(
                    logicalLine, maxWidth, *font, *linePtrs);
                CleanupStack::PushL(buf);

                // one line may create several wrapped lines
                lineCount += linePtrs->Count();

                if (aRasterizeFlags != ERasterizeNone)
                  	{    

                    // create new entries..
                    while (iLines.Count() < lineCount)
                        {
                        SRasterizedLine line;
                        line.iTexture = NULL;
                        line.iGap = 0;
                        iLines.AppendL(line);

                        if (iPictographInterface)
                            {
                            SRasterizedLine pictographline;
                            pictographline.iTexture = NULL;
                            pictographline.iGap = 0;
                            iPictographLines.AppendL(pictographline);                                
                            }
                        }
                    
                   	// Do rasterisation if we want to render to texture.
                    for(TInt i = 0; i < linePtrs->Count(); ++i)
                        {
                        TInt currentLine = (lineCount - linePtrs->Count()) + i;   
          	   	                
    	                if (aRasterizeFlags & ERasterizeText)
    	                    {
                            // rasterize a single line (updates texture in iLines[i].iTexture)
                            RasterizeLineL(linePtrs->At(i), iLines[currentLine]);
    	                    }
    	                    
	                    if (aRasterizeFlags & ERasterizePictographs && iPictographInterface)
	                        {
                            // Rasterize pictographs if needed
                            RasterizePictographLineL(linePtrs->At(i), font, iPictographLines[currentLine]);                                                                 	                            
	                        }
           	                // Get extents from the texture we just created
                            CHuiTexture* tex = iLines[i].iTexture;
                            extents.iHeight += iLines[i].iGap;
                            
                            if(tex)
                                {
                                extents.iWidth = Max(extents.iWidth, tex->Size().iWidth);
                                extents.iHeight += tex->Size().iHeight;
                                }    
                            	                                                         
    	                TBool moreAvailable = (currentLine + 1 < MaxLineCount());
                        if (!moreAvailable)
          	                {
       	                    // Maximum number of lines reached.
       	                    break;
       	                    }
                        }
                  	}
   	            else
   	                {
                    // Don't rasterise or create textures, just get the extents of this text.   	                    
                    for(TInt i = 0; i < linePtrs->Count(); ++i)
                        {  
                        TSize lineExtents = textStyle->LineExtentsL(linePtrs->At(i));
                        extents.iWidth = Max(extents.iWidth, lineExtents.iWidth);
                        extents.iHeight += lineExtents.iHeight;                                                              
                        }
       	            }
                	
                linePtrs->Reset();
                CleanupStack::PopAndDestroy(buf);
                break;
                }

            default:
                break;
            }

        // If we have reached the maximum number of lines, stop building.
        if(IsMaxLineCountReached())
            {
            break;
            }
        }

    HUI_DEBUG(_L("CHuiRasterizedTextMesh::BuildL() - Finished rasterizing text."));

    CleanupStack::PopAndDestroy(linePtrs); linePtrs = 0;

    if (iPictographBitmap)
        {
        iPictographBitmap->Resize(TSize(0, 0));
        }

    HUI_DEBUG(_L("CHuiRasterizedTextMesh::BuildL() - Updating text extents.."));
    // The extents of the mesh depend on how many lines there are.
    SetExtents(extents);

    HUI_DEBUG(_L("CHuiRasterizedTextMesh::BuildL() - Done!"));

    }

void CHuiRasterizedTextMesh::ExpandRectWithShadow(TRect& aRect) const
    {
    if ( iVisual && iLines.Count() )
        {
        CHuiDropShadow* shadowHandler = iVisual->DropShadowHandler();
        if ( shadowHandler &&
             shadowHandler->IsShadowVisible() &&
             iLines[0].iTexture )
            {
            const TInt requestedBlurredSize = HUI_ROUND_FLOAT_TO_INT( 2*shadowHandler->iRadius.Now() );
            THuiTextureHandle shadow;
            // take the first line as an example
            TBool haveShadowTexture = iLines[0].iTexture->GetShadowTexture( shadow,requestedBlurredSize );
            
            if ( haveShadowTexture )
                {
                const TRect shadowRect = shadowHandler->ShadowDrawingTRect( 
                        aRect.iTl,
                        aRect.Size(),
                        shadow.Size(),
                        *iVisual );           
                           
                aRect.BoundingRect( shadowRect );
                }
            }
        }
    }
    

void CHuiRasterizedTextMesh::Draw(CHuiGc& aGc, TReal32 aShadowOpacity) const __SOFTFP
    {
    THuiAlignHorizontal oldHorizAlign = aGc.AlignHorizontal();
    THuiAlignVertical oldVertAlign = aGc.AlignVertical();

    // Because we are using DrawImage, which respects Gc alignments, and the
    // context has already set up the appropriate alignment offset, we must
    // disable the alignment temporarily.
    aGc.SetAlign(EHuiAlignHLeft, EHuiAlignVTop);


    // The actual text.
    DrawLines(aGc, THuiRealPoint(0.f, 0.f), oldHorizAlign, aShadowOpacity);

    if(!iUsingPreRasterizedMesh)
        {
        // Pictographs, if needed.
        DrawPictographLines(aGc, THuiRealPoint(0.f, 0.f), oldHorizAlign);
        }
    
    aGc.SetAlign(oldHorizAlign, oldVertAlign);
    }


void CHuiRasterizedTextMesh::DrawLines(CHuiGc& aGc, const THuiRealPoint& aOffset,
                                       THuiAlignHorizontal aLineAlignment, TReal32 aShadowOpacity) const
    {    
    TInt y = 0;

    // Draw the built lines using THuiImages.
    for(TInt i = 0; i < iLines.Count(); ++i)
        {
        const SRasterizedLine& line = iLines[i];
        if(line.iTexture)
            {

            THuiImage textImage(*line.iTexture);
            THuiRealPoint linePos(0.f, TReal32(y));
            THuiRealSize lineSize = line.iTexture->Size();
                   
            // Do a downward scaling for line texture from TV resolution to LCD resolution.
            if(iTextMeshScale != 1)
                {
                lineSize.iHeight = lineSize.iHeight/iTextMeshScale;
                lineSize.iWidth = lineSize.iWidth/iTextMeshScale;
                }
            
            // Choose the line-specific alignment.
            switch(aLineAlignment)
                {
                case EHuiAlignHRight:
                    linePos.iX = Extents().iWidth - lineSize.iWidth;
                    break;

                case EHuiAlignHCenter:
                    linePos.iX = (Extents().iWidth - lineSize.iWidth) / 2;
                    break;

                default:
                    break;
                }

            
            // Is there a shadow?
            if ( RasterizedShadow() )
                {
                const TInt requestedBlurredSize = HUI_ROUND_FLOAT_TO_INT( 2*iVisual->DropShadowHandler()->iRadius.Now() );
                THuiTextureHandle shadow;
                TBool haveShadowTexture = line.iTexture->GetShadowTexture(shadow,requestedBlurredSize );
                
                if ( haveShadowTexture )
                    {
                    THuiImage shadowImage(shadow);
                    const THuiRealRect shadowDrawingRect = iVisual->DropShadowHandler()->ShadowDrawingRealRect( 
                        linePos,
                        lineSize,
                        shadow.Size(),
                        *iVisual );
                    
                    const TRgb oldColor = aGc.PenColorAlpha();
                    aGc.SetPenColor(iVisual->DropShadowHandler()->Color());
                    aGc.SetPenAlpha(HUI_ROUND_FLOAT_TO_INT(aShadowOpacity * 255.0f));
                    
                    const THuiQuality oldQuality = aGc.Quality();
                    aGc.SetQuality(EHuiQualityFast);
                    
                    aGc.DrawImage(shadowImage, shadowDrawingRect.iTl + aOffset, shadowDrawingRect.Size());
                    
                    aGc.SetPenColorAlpha(oldColor);
                    aGc.SetQuality(oldQuality);
                    }
                }
                
            aGc.DrawImage(textImage, linePos + aOffset, lineSize);

            // Move one line downwards.
            y += TInt(lineSize.iHeight) + line.iGap;
            }

        // Move extra gap downwards.
        y += line.iGap;
        
        // Add line spacing.
        y += iLineSpacing;
        }
    }

void CHuiRasterizedTextMesh::DrawPictographLines(CHuiGc& aGc, const THuiRealPoint& aOffset,
                                       THuiAlignHorizontal aLineAlignment) const
    {
    if (!iPictographInterface || iUsingPreRasterizedMesh)
        {
        return;    
        }
    
    
    TInt y = 0;

    // Draw the built lines using THuiImages.
    for(TInt i = 0; i < iPictographLines.Count(); ++i)
        {
        const SRasterizedLine& line = iPictographLines[i];
        if(line.iTexture)
            {

            THuiImage textImage(*line.iTexture);
            THuiRealPoint linePos(0.f, TReal32(y));
            THuiRealSize lineSize = line.iTexture->Size();

            // Choose the line-specific alignment.
            switch(aLineAlignment)
                {
                case EHuiAlignHRight:
                    linePos.iX = Extents().iWidth - lineSize.iWidth;
                    break;

                case EHuiAlignHCenter:
                    linePos.iX = (Extents().iWidth - lineSize.iWidth) / 2;
                    break;

                default:
                    break;
                }

            aGc.SetPenColor(KRgbWhite);
            aGc.DrawImage(textImage, linePos + aOffset, lineSize);

            // Move one line downwards.
            y += TInt(lineSize.iHeight) + line.iGap;
            }

        // Move extra gap downwards.
        y += line.iGap;
        
        // Add line spacing.
        y += iLineSpacing;
        }
    }


void CHuiRasterizedTextMesh::TextureContentUploaded(CHuiTexture& /*aTexture*/)
    {
    }


void CHuiRasterizedTextMesh::TextureContentReleased(CHuiTexture& /*aTexture*/)
    {
    }


void CHuiRasterizedTextMesh::RestoreTextureContentL(CHuiTexture& /*aTexture*/)
    {
    // We only get one of these, so let's rebuild the text mesh.
    HUI_DEBUG(_L("CHuiRasterizedTextMesh::RestoreTextureContentL() - Rebuilding text."));
    
    // We want to render the mesh so pass true.
    BuildL(ETrue);
    }
void CHuiRasterizedTextMesh::InitPictographsL(CAknPictographInterface* aInterface)
    {
    if(!iUsingPreRasterizedMesh)
        {
        iPictographInterface = aInterface;
        delete iPictographBitmap;
        iPictographBitmap = NULL;
        iPictographBitmap = new (ELeave) CFbsBitmap();    
        User::LeaveIfError( iPictographBitmap->Create(TSize(0, 0), EColor16MA) );        
        }
    }

void CHuiRasterizedTextMesh::BuildPictographsL()
    {
    if(!iUsingPreRasterizedMesh)
        {
        DoBuildL(ERasterizePictographs);
        }
    }

void  CHuiRasterizedTextMesh::UpdateMeshL(const TDesC8& aBuffer)
    {
    iUsingPreRasterizedMesh = ETrue;
    ResetLines();
    RDesReadStream stream(aBuffer);
    TInt count = stream.ReadInt32L();
    for (TInt i=count-1;i>=0;i--)
        {
        // lines are in reverse order
        SRasterizedLine line;
        line.iTexture = dynamic_cast<CHuiTexture*>((MHuiTexture*)stream.ReadInt32L()); //scary
        line.iGap = stream.ReadInt32L();
        iLines.InsertL(line, 0);
        }
    TSize extents;
    extents.iWidth = stream.ReadInt32L();
    extents.iHeight = stream.ReadInt32L();
    SetExtents(extents);
    stream.Close();
    
    if (RasterizedShadow()) // update shadow
        {
        for (TInt i = iLines.Count()-1; i >=0; i-- )
            {
            if (iLines[i].iTexture)
                {
                const TInt requestedBlurredSize = HUI_ROUND_FLOAT_TO_INT( 2*iVisual->DropShadowHandler()->iRadius.Now() );
                iLines[i].iTexture->CreateShadowTextureL( requestedBlurredSize, EHuiTextureShadowStyleRasterizedText );
                }
            }
        }
    }