sl@0: // Copyright (c) 2005-2010 Nokia Corporation and/or its subsidiary(-ies).
sl@0: // All rights reserved.
sl@0: // This component and the accompanying materials are made available
sl@0: // under the terms of "Eclipse Public License v1.0"
sl@0: // which accompanies this distribution, and is available
sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html".
sl@0: //
sl@0: // Initial Contributors:
sl@0: // Nokia Corporation - initial contribution.
sl@0: //
sl@0: // Contributors:
sl@0: //
sl@0: // Description:
sl@0: // Contains client-side shaper functionality.
sl@0: // 
sl@0: //
sl@0: 
sl@0: #include "ShapeImpl.h"
sl@0: #include "ShapeInfo.h"
sl@0: #include <textbase.h>
sl@0: #include "TextBasePanic.h"
sl@0: 
sl@0: GLREF_C void TextBasePanic(TInt aError);
sl@0: 
sl@0: /** Construct an RShapeInfo. */
sl@0: /** @internalComponent */
sl@0: EXPORT_C RShapeInfo::RShapeInfo()
sl@0: 	: iFont(0), iHeader(0), iEndOfShapedText(-1), iContextualProcessFunc(0) {}
sl@0: 
sl@0: /** Perform shaping on the text in aText between aStartOfTextToShape and
sl@0: aEndOfTextToShape, based on the script conventions implied by aScriptCode.
sl@0: @param aFont The font to use for the shaping.
sl@0: @param aText The text, including context.
sl@0: @param aStartOfTextToShape
sl@0: 	The start position within aText of the text to be shaped.
sl@0: @param aEndOfTextToShape
sl@0: 	The end position within aText of the text to be shaped.
sl@0: @param aScriptCode The script code for the script being shaped.
sl@0: @param aLanguageCode The language code for the language being shaped.
sl@0: @return
sl@0: 	KErrNone if the text was successfully shaped, KErrNotSupported if aFont has
sl@0: 	no shaper, KErrCouldNotConnect if the font bitmap server has not been
sl@0: 	started.
sl@0: */
sl@0: TInt RShapeInfo::Open(const CFont* aFont, const TDesC& aText,
sl@0: 	TInt aStartOfTextToShape, TInt aEndOfTextToShape,
sl@0: 	TInt aScriptCode, TInt aLanguageCode)
sl@0: 	{
sl@0: 	TEXTBASE_ASSERT_DEBUG(0 <= aStartOfTextToShape,
sl@0: 		ETextBasePanic_InvalidInputParam);
sl@0: 	TEXTBASE_ASSERT_DEBUG(aStartOfTextToShape <= aEndOfTextToShape,
sl@0: 		ETextBasePanic_InvalidInputParam);
sl@0: 	TEXTBASE_ASSERT_DEBUG(aEndOfTextToShape <= aText.Length(),
sl@0: 		ETextBasePanic_InvalidInputParam);
sl@0: 	iFont = aFont;
sl@0: 	TFontShapeFunctionParameters param;
sl@0: 	param.iText = &aText;
sl@0: 	param.iStart = aStartOfTextToShape;
sl@0: 	param.iEnd = aEndOfTextToShape;
sl@0: 	param.iScript = aScriptCode;
sl@0: 	param.iLanguage = aLanguageCode;
sl@0: 	const TInt r = aFont->ExtendedFunction(KFontGetShaping, &param);
sl@0: 	iHeader = r == KErrNone ? param.iShapeHeaderOutput : 0;
sl@0: 	if(iHeader)
sl@0: 		iEndOfShapedText = aEndOfTextToShape;
sl@0: 	return r;
sl@0: 	}
sl@0: 
sl@0: /** Frees the memory associated with this shaping information. */
sl@0: /** @internalComponent */
sl@0: EXPORT_C void RShapeInfo::Close()
sl@0: 	{
sl@0: 	if (iHeader)
sl@0: 		{
sl@0: 		TFontShapeDeleteFunctionParameters param;
sl@0: 		param.iShapeHeader = iHeader;
sl@0: 		iFont->ExtendedFunction(KFontDeleteShaping, &param);
sl@0: 		iHeader = NULL;
sl@0: 		iEndOfShapedText = -1;
sl@0: 		// We don't reset iSingleContextChar because we want the context to remain throughout,
sl@0: 		// even when the session is closed. It would eventually simply go out of scope.
sl@0: 		}
sl@0: 	}
sl@0: 
sl@0: /** Returns the number of glyphs in the shaped output.
sl@0: @return The number of glyphs. Also equal to the size of the Glyphs() array and
sl@0: the GlyphPositions() array. */
sl@0: TInt RShapeInfo::GlyphCount() const
sl@0: 	{
sl@0: 	TEXTBASE_ASSERT_ALWAYS(iHeader, ETextBasePanic_Invariant);
sl@0: 	return iHeader->iGlyphCount;
sl@0: 	}
sl@0: 
sl@0: /** Returns the array of glyphs. These must be ORed with 0x80000000 to make
sl@0: glyph numbers that functions like CFbsFont::Rasterize can accept to avoid
sl@0: confusing glyph numbers with Unicode character numbers.
sl@0: @return The glyph array. The size of this array is RShapeInfo::GlyphCount
sl@0: @see GlyphCount */
sl@0: const TInt32* RShapeInfo::Glyphs() const
sl@0: 	{
sl@0: 	TEXTBASE_ASSERT_ALWAYS(iHeader, ETextBasePanic_Invariant);
sl@0: 	return reinterpret_cast<const TInt32*>(iHeader->iBuffer);
sl@0: 	}
sl@0: 
sl@0: /** Returns the array of positions for the glyphs returned by Glyphs, and the
sl@0: total advance for the text.
sl@0: @return
sl@0: 	Array of glyph positions in pixels, relative to the pen position before
sl@0: 	the glyphs are drawn. The array has GlyphCount() + 1 entries, as the
sl@0: 	last entry represents the total advance of the text. */
sl@0: const RShapeInfo::TPoint16* RShapeInfo::GlyphPositions() const
sl@0: 	{
sl@0: 	TEXTBASE_ASSERT_ALWAYS(iHeader, ETextBasePanic_Invariant);
sl@0: 	return reinterpret_cast<const RShapeInfo::TPoint16*>(iHeader->iBuffer
sl@0: 		+ ((iHeader->iGlyphCount) << 2));
sl@0: 	}
sl@0: 
sl@0: /** Returns the pen advance these glyphs require.
sl@0: @return The pen advance; where to move the pen after drawing all the glyphs. */
sl@0: RShapeInfo::TPoint16 RShapeInfo::Advance() const
sl@0: 	{
sl@0: 	TEXTBASE_ASSERT_ALWAYS(iHeader, ETextBasePanic_Invariant);
sl@0: 	RShapeInfo::TPoint16 r;
sl@0: 	r.iX = *reinterpret_cast<const TInt16*>(iHeader->iBuffer
sl@0: 		+ (iHeader->iGlyphCount << 3));
sl@0: 	r.iY = *reinterpret_cast<const TInt16*>(iHeader->iBuffer
sl@0: 		+ (iHeader->iGlyphCount << 3) + 2);
sl@0: 	return r;
sl@0: 	}
sl@0: 
sl@0: /** Returns the array of indices.
sl@0: @return
sl@0: 	Indices[n] is the position in the input text that produced Glyphs[n].
sl@0: */
sl@0: const TInt16* RShapeInfo::Indices() const
sl@0: 	{
sl@0: 	TEXTBASE_ASSERT_ALWAYS(iHeader, ETextBasePanic_Invariant);
sl@0: 	return reinterpret_cast<const TInt16*>(iHeader->iBuffer
sl@0: 		+ (iHeader->iGlyphCount << 3) + 4);
sl@0: 	}
sl@0: 	
sl@0: TInt RShapeInfo::EndOfShapedText()
sl@0: 	{
sl@0: 	return iEndOfShapedText;
sl@0: 	}
sl@0: 
sl@0: /** Checks if this shaping information is still occupying memory. */
sl@0: EXPORT_C TBool RShapeInfo::IsOpen()
sl@0: 	{
sl@0: 	if(iHeader && iHeader->iGlyphCount >= 0 && iHeader->iCharacterCount >=0)
sl@0: 		return ETrue;
sl@0: 	else
sl@0: 		return EFalse;
sl@0: 		
sl@0: 	}
sl@0: 
sl@0: void RShapeInfo::SetContext(TAny* aContextualProcessFunc)
sl@0: 	{
sl@0: 	iContextualProcessFunc = aContextualProcessFunc;
sl@0: 	}
sl@0: 	
sl@0: TAny* RShapeInfo::GetContext()
sl@0: 	{
sl@0: 	return iContextualProcessFunc;
sl@0: 	}
sl@0: