graphicsdeviceinterface/bitgdi/sbit/TEXT.CPP
author Faisal Memon <faisal.memon@nokia.com>
Fri, 25 Jun 2010 17:49:58 +0100
branchEGL_MERGE
changeset 105 158b2308cc08
parent 0 5d03bc08d59c
permissions -rw-r--r--
Fix def files so that the implementation agnostic interface definition has no non-standards defined entry points, and change the eglrefimpl specific implementation to place its private entry points high up in the ordinal order space in the implementation region, not the standards based entrypoints region.

// Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
//
// Initial Contributors:
// Nokia Corporation - initial contribution.
//
// Contributors:
//
// Description:
//

#include <fntstore.h>
#include <bitdraw.h>
#include <bitstd.h>
#include <bitdev.h>
#include "BITPANIC.H"
#include <shapeinfo.h>
#include <bmalphablend.h>
#include <bitdrawinterfaceid.h>
#include <graphics/fbsrasterizer.h>
#include "bitgcextradata.h"
#include <graphics/gdi/gdiconsts.h>
#include <graphics/gdi/gdistructs.h>


/** Draws text at the last print position.

@param aText The text string to be drawn. */
EXPORT_C void CFbsBitGc::DrawText(const TDesC& aText)
	{
	TTextParameters* param = NULL;
	DrawText(aText,param,iLastPrintPosition,ELeft,CFont::EHorizontal);
	}

/** Draws text at the specified position and updates the print position.

@param  aText The text string to be drawn
@param aCoords Coordinates to draw the text at. */
EXPORT_C void CFbsBitGc::DrawText(const TDesC& aText,const TPoint& aCoords)
	{
	TTextParameters* param = NULL;
	DrawText(aText,param,aCoords,ELeft,CFont::EHorizontal);
	}


/** Draws text clipped to the specified rectangle.

@param aText The text string to be drawn 
@param aBox The clipping rectangle. */
EXPORT_C void CFbsBitGc::DrawText(const TDesC& aText,const TRect& aBox)
	{
	TTextParameters* param = NULL;
	DrawText(aText,param,aBox);
	}


/** Draws text clipped to the specified rectangle using a baseline offset,
horizontal alignment and a margin.

@param  aText The text string to be drawn
@param aBox The clipping rectangle.
@param  aBLOff An offset in pixels for the baseline from the normal position
        (bottom of the rectangle minus the descent of the font).
@param  aHrz Horizontal alignment option relative to the specified rectangle.
@param aMargin Offset to add to the position as calculated using specified 
		rectangle. */	
EXPORT_C void CFbsBitGc::DrawText(const TDesC& aText,const TRect& aBox,TInt aBLOff,
								  TTextAlign aHrz,TInt aMargin)
    {
    TTextParameters* param = NULL;
	DrawText(aText,param,aBox,aBLOff,-1,aHrz,aMargin);
	}

/** Draws text clipped to the specified rectangle.

@param  aText The text string to be drawn
@param aBox The clipping rectangle. */	
EXPORT_C void CFbsBitGc::DrawText(const TDesC& aText,const TRect& aBox,
								  TInt aBLOff,TInt /*aTextWidth*/,
								  TTextAlign aHrz,TInt aMargin)
    {
// aTextWidth is not used here - try to abolish this - I think it is unneeded
	TPoint p(aBox.iTl);
	p.iY += aBLOff;
	switch (aHrz)
		{
		case ELeft: p.iX += aMargin; break;
		case ERight: p.iX = aBox.iBr.iX - aMargin; break;
		case ECenter: p.iX += aBox.Width() / 2 + aMargin; break;
		}
	TTextParameters* param = NULL;
	DrawText(aText,param,p,aHrz,CFont::EHorizontal,&aBox);
	}


/** The general DrawText routine that implements all the others.

@param aText the text to be drawn
@param aPosition the origin of the text
@param aAlignment left, centred or right, around aPosition; not used if drawing vertically
@param aDirection direction: left to right, right to left, or top to bottom
@param aBox if non-null, filled before the text is drawn
@param aTextBounds if non-null returns the bounding box of the text
*/ 
void CFbsBitGc::DrawText(const TDesC& aText,const TTextParameters* aParam,const TPoint& aPosition,TTextAlign aAlignment,
						 CFont::TTextDirection aDirection,const TRect* aBox)
   {
	// sanity checks
	BG_ASSERT_ALWAYS(iDevice,EBitgdiPanicNoDevicePresent);
	BG_ASSERT_ALWAYS(iFont.Handle() != 0,EBitgdiPanicNoFontSelected);
	const CBitmapFont* bitmap_font = iFont.Address();
	BG_ASSERT_ALWAYS(bitmap_font != 0,EBitgdiPanicNoFontSelected);

	// anything to do?
	if (!aBox && !aText.Length())
		return;

	CFbsDrawDevice* drawDevice = iDevice->iDrawDevice;

	TRect deviceRect;
	drawDevice->GetDrawRect(deviceRect);

	// measure the text
	CFont::TMeasureTextInput measure_text_input;
	measure_text_input.iCharJustNum = iCharJustNum;
	measure_text_input.iCharJustExcess = iCharJustExcess;
	measure_text_input.iWordJustNum = iWordJustNum;
	measure_text_input.iWordJustExcess = iWordJustExcess;
	measure_text_input.iFlags |= CFont::TMeasureTextInput::EFVisualOrder;
	if (aParam)
		{
		BG_ASSERT_ALWAYS(aParam->iStart < aParam->iEnd ,EBitgdiPanicInvalidParameter);
		measure_text_input.iStartInputChar = aParam->iStart;
		measure_text_input.iEndInputChar = Min(aText.Length(),aParam->iEnd);
		}
	CFont::TMeasureTextOutput measure_text_output;
	const int advance = iFont.MeasureText(aText,&measure_text_input,&measure_text_output);
	TRect text_bounds = measure_text_output.iBounds;
	TInt underlineStrikeoutOffset;
	
	//this call is only needed in the case of linked fonts
	//should this pass by one structure?
	underlineStrikeoutOffset= BaselineCorrection();
	
	if (iUnderline == EUnderlineOn)
		{
		TInt underline_top = 0, underline_bottom = 0;
		TInt err = GetUnderlineMetrics(underline_top,underline_bottom);
		underline_top+=underlineStrikeoutOffset;
		underline_bottom+=underlineStrikeoutOffset;
		BG_ASSERT_DEBUG(err == KErrNone, EBitgdiPanicInvalidArg);
		text_bounds.iTl.iY = Min(text_bounds.iTl.iY,underline_top);
		text_bounds.iBr.iY = Max(text_bounds.iBr.iY,underline_bottom);
		}
	if (iStrikethrough == EStrikethroughOn)
		{
		TInt strike_top = 0,strike_bottom = 0;
		GetStrikethroughMetrics(strike_top,strike_bottom);
		strike_top+=underlineStrikeoutOffset;
		strike_bottom+=underlineStrikeoutOffset;
		text_bounds.iTl.iY = Min(text_bounds.iTl.iY,strike_top);
		text_bounds.iBr.iY = Max(text_bounds.iBr.iY,strike_bottom);
		}
	if (iUnderline == EUnderlineOn || iStrikethrough == EStrikethroughOn)
		{
		if (aDirection == CFont::EHorizontal)
			{
			text_bounds.iTl.iX = Min(text_bounds.iTl.iX, 0);
			text_bounds.iBr.iX = Max(text_bounds.iBr.iX, advance);
			}
		else
			{
			text_bounds.iTl.iY = Min(text_bounds.iTl.iY, 0);
			text_bounds.iBr.iY = Max(text_bounds.iBr.iY, advance);
			}
		}

	// work out the text origin and new drawing position
 	TPoint text_origin = aPosition;
 	if (aDirection != CFont::EVertical)
 		{
 		const TInt leftSideBearing = Min(text_bounds.iTl.iX, 0);
 		const TInt rightSideBearing = Max(text_bounds.iBr.iX, advance);
 		switch (aAlignment)
 			{
			// We are forbidding side-bearings to leak over the sides here,
			// but still keeping the start and end pen positions within bounds.
			case ELeft:
				text_origin.iX -= leftSideBearing;
				break;
			case ERight:
				text_origin.iX -= rightSideBearing;
				break;
			case ECenter:
				// Centre is the average of left and right
				text_origin.iX -= (leftSideBearing + rightSideBearing) >> 1;
				break;
			default:
				break;
 			}
		}
	iLastPrintPosition = text_origin;
	if (aDirection == CFont::EHorizontal)
		iLastPrintPosition.iX += advance;
	else
		iLastPrintPosition.iY += advance;
	text_origin.iY += bitmap_font->iAlgStyle.iBaselineOffsetInPixels;
	text_bounds.Move(text_origin);
	text_origin += iOrigin;

	// determine clipping rectangle
	TRect clip_rect = aBox ? *aBox : text_bounds;
	AddRect(clip_rect);
	clip_rect.Move(iOrigin);

	if (UserClipRect(clip_rect))
		{
		if (iAutoUpdateJustification)
			UpdateJustification(aText,aParam);
		return; // nothing to do
		}

	SetupDevice();
	iDevice->DrawingBegin(&iBrushBitmap);
	CFbsRasterizer* brushRasterizer = PrepareRasterizerForExtendedBitmap(iBrushBitmap);

	// fill the box if necessary
	if (aBox)
		{
		TRect fill_box = *aBox;
		fill_box.Move(iOrigin);
		RectFill(fill_box);
		}

	// decide which drawing routine to call
	const TBool bold = bitmap_font->iAlgStyle.IsBold();
	const TBool italic = bitmap_font->iAlgStyle.IsItalic();
	const TBool multiw = bitmap_font->iAlgStyle.WidthFactor() > 1;
	const TBool multih = bitmap_font->iAlgStyle.HeightFactor() > 1;

	TOpenFontMetrics metrics;
	iFont.GetFontMetrics(metrics);
	const TInt maxwidth = metrics.MaxWidth();
	// extext will be TRUE, if font is bold/italic/underline/strikethrough/anti-aliased or it 
	// has shadow/outline effects ON. Depending on these properties it will call the proper draw routine.
	TBool extext = FALSE;
	TBool normaltext = FALSE;
	const TBool anti_aliased = (bitmap_font->GlyphBitmapType() == EAntiAliasedGlyphBitmap);
	const TBool outlineAndShadow = (bitmap_font->GlyphBitmapType() == EFourColourBlendGlyphBitmap);
	if (anti_aliased || outlineAndShadow)
		{
		if ((outlineAndShadow) && !(iBrushStyle == ENullBrush || iBrushStyle == ESolidBrush))
			{
			//For future compatibility it is better if brush style of ENullBrush or ESolidBrush is used 
			//when drawing outline and shadow fonts.
			BG_PANIC_ALWAYS(EBitgdiPanicInvalidBrushStyle);
			}
		extext = TRUE;
		}
	else if (maxwidth > 30 || text_bounds.Height() > 32 || multiw || multih)
		{
		}
	else if (iUnderline == EUnderlineOn || bold || italic || iStrikethrough == EStrikethroughOn || 
			 iCharJustNum > 0 || iWordJustNum > 0)
		extext = TRUE;
	else
		normaltext = TRUE;

	const TInt charjustexcess = iCharJustExcess;
	const TInt charjustnum = iCharJustNum;
	const TInt wordjustexcess = iWordJustExcess;
	const TInt wordjustnum = iWordJustNum;

	// draw the text to all clip rectangles in turn
	int clip_rects = iDefaultRegionPtr->Count();
	for (int i = 0; i < clip_rects; i++)
		{
		iClipRect = (*iDefaultRegionPtr)[i];
		if (!iClipRect.Intersects(clip_rect))
			continue;

#ifdef _DEBUG
		BG_ASSERT_DEBUG(iClipRect.iTl.iX >= deviceRect.iTl.iX, EBitgdiPanicOutOfBounds);
		BG_ASSERT_DEBUG(iClipRect.iTl.iY >= deviceRect.iTl.iY, EBitgdiPanicOutOfBounds);
		BG_ASSERT_DEBUG(iClipRect.iBr.iX <= deviceRect.iBr.iX, EBitgdiPanicOutOfBounds);
		BG_ASSERT_DEBUG(iClipRect.iBr.iY <= deviceRect.iBr.iY, EBitgdiPanicOutOfBounds);
#endif

		iClipRect.Intersection(clip_rect);

		// Set up the parameter block for character positioning.
		CFont::TPositionParam param;
		param.iDirection = static_cast<TInt16>(aDirection);
		param.iText.Set(aText);
		TInt endDraw = aText.Length();
		if (aParam)
			{
			param.iPosInText = aParam->iStart;
			endDraw = Min(aText.Length(),aParam->iEnd);
			}
		else
			param.iPosInText = 0;
		param.iPen = text_origin;

		// Draw the text.
		if (normaltext)
			DoDrawText(param,endDraw);
		else if (extext)
			DoDrawTextEx(param,bitmap_font,endDraw,underlineStrikeoutOffset);
		else
			DoDrawTextLarge(param,bitmap_font,endDraw);
		
		/*
		Reset the justification parameters to their original values.
		These will be updated as required later in code.
		*/
		iCharJustExcess = charjustexcess;
		iCharJustNum = charjustnum;
		iWordJustExcess = wordjustexcess;
		iWordJustNum = wordjustnum;

		drawDevice->UpdateRegion(iClipRect);
		}

	if (brushRasterizer)
		{
		brushRasterizer->EndBitmap(iBrushBitmap.SerialNumber());
		}
	iDevice->DrawingEnd(&iBrushBitmap);
	if (iAutoUpdateJustification)
		UpdateJustification(aText,aParam);
	}

void CFbsBitGc::DoDrawText(CFont::TPositionParam& aParam, const TInt aEnd)
	{
	//const int n = aParam.iText.Length();
	RShapeInfo shapeInfo;
	while (aParam.iPosInText < /*n*/aEnd)
		{
		if (iFont.GetCharacterPosition2(aParam, shapeInfo))
			{
			const CFont::TPositionParam::TOutput* output = aParam.iOutput;
			for (int i = 0; i < aParam.iOutputGlyphs; i++, output++)
				DoDrawCharacter(output->iBounds.iTl,output->iBitmapSize,output->iBitmap);
			}
		}
	if (shapeInfo.IsOpen())
		shapeInfo.Close();
		
	}

void CFbsBitGc::DoDrawCharacter(const TPoint& aTopLeft,
								const TSize& aDataSize,
								const TUint8* aData)
	{
	/*
	Divert if the character is larger than expected; the criterion
	for choosing this function is only a heuristic, because it's perfectly legal for
	a character's bitmap to be wider than its escapement.

	Use a dummy value (0) for semi-ascent because this character is not italic and so semi-ascent
	is irrelevant; it's used for pseudo-italic slanting.
	*/
	TInt dataheight = aDataSize.iHeight;
	TInt datalength = aDataSize.iWidth;
	if (datalength > 30 || dataheight > 32)
		{
		DoDrawCharacterExLarge(aTopLeft,aDataSize,aData,FALSE,FALSE,0,1,1);
		return;
		}
	
	TInt bitindex=0;
	TInt16 repeatcount=0;
	TUint32 binarydata[32];
	TUint32* binarydataptr=binarydata;
	TUint32* binarydataptrlimit;
	for(TInt charline=0;charline<dataheight;charline+=repeatcount) // for lines in the character...
		{
		repeatcount=Load16(aData+(bitindex>>3));
		repeatcount>>=bitindex&7;
		TInt multilineflag=repeatcount&1;
		repeatcount>>=1;
		repeatcount&=0xf;
		bitindex+=5;
		binarydataptrlimit=binarydata+charline+repeatcount;
		if(multilineflag)
			{
			while(binarydataptr<binarydataptrlimit)
				{
				TInt chardataoffsetptr=TInt(aData)+(bitindex>>3);
				TUint32* chardataword=(TUint32*)(chardataoffsetptr&~3);
				TInt bitshift=bitindex&7;
				bitshift+=(chardataoffsetptr&3)<<3;
				*binarydataptr=(*chardataword++)>>bitshift;
				if(bitshift) *binarydataptr|=(*chardataword<<(32-bitshift));
				bitindex+=datalength;
				binarydataptr++;
				}
			}
		else
			{
			TInt chardataoffsetptr=TInt(aData)+(bitindex>>3);
			TUint32* chardataword=(TUint32*)(chardataoffsetptr&~3);
			TInt bitshift=bitindex&7;
			bitshift+=(chardataoffsetptr&3)<<3;
			TUint32 data=(*chardataword++)>>bitshift;
			if(bitshift) data|=(*chardataword<<(32-bitshift));
			while(binarydataptr<binarydataptrlimit)
				*binarydataptr++=data;
			bitindex+=datalength;
			}
		}
	TPoint topleft(aTopLeft);
	binarydataptr=ClipBinaryArray(binarydata,binarydata+dataheight,1,datalength,dataheight,topleft);
	if(datalength>0 && dataheight>0)
		iDevice->iDrawDevice->WriteBinary(topleft.iX,topleft.iY,binarydataptr,datalength,dataheight,iPenColor,iDrawMode);
	}

/** 
@internalTechnology

This function retrieves the baseline offset from the metrics of the text currently being drawn.
This is used to alter the positioning of underline and strikethrough on a linked font

@return The baseline correction associated with the currently used font.
*/	
TInt CFbsBitGc::BaselineCorrection()
	{
	TOpenFontMetrics metrics;
	if (iFont.GetFontMetrics(metrics))
		return metrics.BaselineCorrection();
	else
		return 0;
	}

void CFbsBitGc::DoDrawTextEx(CFont::TPositionParam& aParam,const CBitmapFont* font, const TInt aEnd, const TInt aUnderlineStrikethroughOffset)
	{
	const TInt charclipping = iClipRect.iBr.iX;
	TPoint start_pen = aParam.iPen;
	const TBool bold = font->iAlgStyle.IsBold();
	const TBool italic = font->iAlgStyle.IsItalic();
	const TGlyphBitmapType glyphBitmapTypeForFont = font->GlyphBitmapType();
	const TBool outlineShadowOrAntialiased = ((glyphBitmapTypeForFont == EAntiAliasedGlyphBitmap) ||
												(glyphBitmapTypeForFont == EFourColourBlendGlyphBitmap));

	TInt underline_top = 0, underline_bottom = 0;
	if (iUnderline == EUnderlineOn)
		{
		TInt err = GetUnderlineMetrics(underline_top,underline_bottom);
		underline_top+=aUnderlineStrikethroughOffset;
		underline_bottom+=aUnderlineStrikethroughOffset;
		BG_ASSERT_DEBUG(err == KErrNone, EBitgdiPanicInvalidArg);
		}
	TInt strike_top = 0, strike_bottom = 0;
	if (italic || iStrikethrough == EStrikethroughOn)
		{
		GetStrikethroughMetrics(strike_top,strike_bottom);
		strike_top+=aUnderlineStrikethroughOffset;
		strike_bottom+=aUnderlineStrikethroughOffset;
		}

	CFbsDrawDevice* drawDevice = iDevice->iDrawDevice;
	RShapeInfo shapeInfo;
	while (aParam.iPosInText < aEnd)
		{
		if (!iFont.GetCharacterPosition2(aParam, shapeInfo))
			continue;
		TInt adjustment = 0;
		if(iCharJustExcess && iCharJustNum > 0) // character clipping/justification
			{
			adjustment = CGraphicsContext::JustificationInPixels(iCharJustExcess,iCharJustNum);
			if(adjustment < 0)
				iClipRect.iBr.iX = Min(aParam.iPen.iX + adjustment,iClipRect.iBr.iX);
			}

		const CFont::TPositionParam::TOutput* output = aParam.iOutput;
		int semi_ascent = start_pen.iY + strike_top;

		for (int i = 0; i < aParam.iOutputGlyphs; i++, output++)
			{
			//get the character metrics for the glyph type
			TOpenFontCharMetrics characterParams;
			const TUint8* bitmap;
			TSize size;
			//note may now be using a glyph code, and not a character
			iFont.GetCharacterData(aParam.iOutput[i].iCode,characterParams,bitmap,size);
			TGlyphBitmapType glyphType = characterParams.GlyphType();
			
			switch (glyphType)
				{
				case EAntiAliasedGlyphBitmap:
				case EFourColourBlendGlyphBitmap:
					DoDrawCharacterAntiAliased(output->iBounds.iTl,output->iBitmapSize,output->iBitmap,glyphType);
					break;

				case EDefaultGlyphBitmap:
				case EMonochromeGlyphBitmap:
					DoDrawCharacterEx(output->iBounds.iTl,output->iBitmapSize,output->iBitmap,bold,italic,semi_ascent);
					break;

				default:
					//if the outline or shadow is not specified for the character, then use the font setting
					if (outlineShadowOrAntialiased)
						{
						DoDrawCharacterAntiAliased(output->iBounds.iTl,output->iBitmapSize,output->iBitmap,glyphBitmapTypeForFont);			
						}
					else
						{
						DoDrawCharacterEx(output->iBounds.iTl,output->iBitmapSize,output->iBitmap,bold,italic,semi_ascent);
						}			 
					break;
				}
			}

		iClipRect.iBr.iX = charclipping;
		if (adjustment)
			aParam.iPen.iX += adjustment;
		if (iWordJustExcess > 0 && iWordJustNum > 0 && aParam.iOutput[0].iCode == 0x0020) // word justification
			{
			adjustment = CGraphicsContext::JustificationInPixels(iWordJustExcess,iWordJustNum);
			aParam.iPen.iX += adjustment;
			}
		}
	if (shapeInfo.IsOpen())
		shapeInfo.Close();

	if (iUnderline == EUnderlineOn)
		{
		TRect ul(start_pen.iX,start_pen.iY + underline_top,aParam.iPen.iX,start_pen.iY + underline_bottom);
		if(ul.Intersects(iClipRect)) // checks for empty aRect as well
			{
			ul.Intersection(iClipRect);
			drawDevice->WriteRgbMulti(ul.iTl.iX,ul.iTl.iY,ul.iBr.iX-ul.iTl.iX,ul.iBr.iY-ul.iTl.iY,iPenColor,iDrawMode);
			}
		}

	if (iStrikethrough == EStrikethroughOn)
		{
		TRect st(start_pen.iX,start_pen.iY + strike_top,aParam.iPen.iX,start_pen.iY + strike_bottom);
		if(st.Intersects(iClipRect)) // checks for empty aRect as well
			{
			st.Intersection(iClipRect);
			drawDevice->WriteRgbMulti(st.iTl.iX,st.iTl.iY,st.iBr.iX-st.iTl.iX,st.iBr.iY-st.iTl.iY,iPenColor,iDrawMode);
			}
		}
	}

void CFbsBitGc::DoDrawCharacterEx(const TPoint& aTopLeft,
								  const TSize& aDataSize,
								  const TUint8* aData,
								  TBool aBold,TBool aItalic,TInt aSemiAscent)
	{
	/*
	Divert if the character is larger than expected; the criterion
	for choosing this function is only a heuristic, because it's perfectly legal for
	a character's bitmap to be wider than its escapement.
	*/
	TInt datalength = aDataSize.iWidth;
	TInt dataheight = aDataSize.iHeight;
	if (datalength > 30 || dataheight > 32)
		{
		DoDrawCharacterExLarge(aTopLeft,aDataSize,aData,aBold,aItalic,aSemiAscent,1,1);
		return;
		}

	TInt bitindex=0;
	TInt16 repeatcount=0;
	TUint32 binarydata[32];
	TUint32* binarydataptr=binarydata;
	TUint32* binarydataptrlimit;
	for(TInt charline=0;charline<dataheight;charline+=repeatcount) // for lines in the character...
		{
		repeatcount=Load16(aData+(bitindex>>3));
		repeatcount>>=bitindex&7;
		TInt multilineflag=repeatcount&1;
		repeatcount>>=1;
		repeatcount&=0xf;
		bitindex+=5;
		binarydataptrlimit=binarydata+charline+repeatcount;
		if(multilineflag)
			{
			while(binarydataptr<binarydataptrlimit)
				{
				CopyCharWord(binarydataptr,aData+(bitindex>>3),bitindex&7);
				bitindex+=datalength;
				binarydataptr++;
				}
			}
		else
			{
			TUint32 data=0;
			CopyCharWord(&data,aData+(bitindex>>3),bitindex&7);
			while(binarydataptr<binarydataptrlimit)
				*binarydataptr++=data;
			bitindex+=datalength;
			}
		}
	binarydataptr=binarydata;
	binarydataptrlimit=binarydata+dataheight;
	if(aBold)
		{
		TInt sparemask=(0xffffffff>>(32-datalength));
		while(binarydataptr<binarydataptrlimit)
			{
			*binarydataptr&=sparemask;
			*binarydataptr|=(*binarydataptr<<1);
			++binarydataptr;
			}
		binarydataptr=binarydata;
		datalength++;
		}
	if(aItalic)
		{
		TInt skewlevel=aSemiAscent-aTopLeft.iY;
		TUint32 sparemask=(0xffffffff>>(32-datalength));
		binarydataptrlimit=binarydata+skewlevel;
		while(binarydataptr<binarydataptrlimit)
			*binarydataptr++<<=1;
		binarydataptrlimit=binarydata+dataheight;
		while(binarydataptr<binarydataptrlimit)
			*binarydataptr++&=sparemask;
		binarydataptr=binarydata;
		datalength++;
		}
	TPoint topleft(aTopLeft);
	binarydataptr=ClipBinaryArray(binarydata,binarydata+dataheight,1,datalength,dataheight,topleft);
	if(datalength>0 && dataheight>0)
		iDevice->iDrawDevice->WriteBinary(topleft.iX,topleft.iY,binarydataptr,datalength,dataheight,iPenColor,iDrawMode);
	}

/** 
@internalTechnology

This function draws an anti-aliased character.

@param aTopLeft The position to output the character
@param aDataSize The size of the bitmap
@param aData the bitmap for outputt in their TOpenFontCharMetrics
@param aGlyphType the glyph type for the character
*/
void CFbsBitGc::DoDrawCharacterAntiAliased(const TPoint& aTopLeft,
										   const TSize& aDataSize,
										   const TUint8* aData,
										   const TGlyphBitmapType aGlyphType)
	{
	const int top_row = Max(0,iClipRect.iTl.iY - aTopLeft.iY);
	const int bottom_row = Min(aDataSize.iHeight,iClipRect.iBr.iY - aTopLeft.iY);
	const int left_col = Max(0,iClipRect.iTl.iX - aTopLeft.iX);
	const int right_col = Min(aDataSize.iWidth,iClipRect.iBr.iX - aTopLeft.iX);
	const TUint8* p = aData + top_row * aDataSize.iWidth + left_col;
	const int x = aTopLeft.iX + left_col;
	int y = aTopLeft.iY + top_row;
	const int cols = right_col - left_col;
	const TUint32 penColor = iPenColor.Internal();
	const TUint32 shadowColor = iFbsBitGcExtraData->ShadowColor().Internal();
	const TUint32 brushColor = iBrushColor.Internal();

	if (EFourColourBlendGlyphBitmap == aGlyphType)
		{
		MOutlineAndShadowBlend* outlineAndShadow = NULL;
		const TInt err = iDevice->iDrawDevice->GetInterface(KOutlineAndShadowInterfaceID, reinterpret_cast <TAny*&> (outlineAndShadow));
		if(err == KErrNone) 
			{
			//There is a support for the interface with KOutlineAndShadowInterface id.
			for (int row = top_row; row < bottom_row; row++, p += aDataSize.iWidth, y++)
				outlineAndShadow->WriteRgbOutlineAndShadow(x, y, cols, penColor, shadowColor, brushColor, p);
			}
		else
			{
			// Assert if MOutlineAndShadowBlend interface is not implemented
			BG_ASSERT_DEBUG(outlineAndShadow, EBitgdiPanicInvalidInterfaceHandle);
			}
		}
	else
		{
		for (int row = top_row; row < bottom_row; row++, p += aDataSize.iWidth, y++)
			iDevice->iDrawDevice->WriteRgbAlphaMulti(x,y,cols,iPenColor,p);
		}
	}

void CFbsBitGc::DoDrawTextLarge(CFont::TPositionParam& aParam,const CBitmapFont* font,const TInt aEnd)
	{
	const TInt charclipping = iClipRect.iBr.iX;
	TPoint start_pen = aParam.iPen;
	const TInt strikeheight = start_pen.iY - (font->CBitmapFont::DoAscentInPixels() * 5/12) - 1;
	const TBool bold = font->iAlgStyle.IsBold();
	const TBool italic = font->iAlgStyle.IsItalic();
	const TInt widthfactor=font->iAlgStyle.WidthFactor();
	const TInt heightfactor=font->iAlgStyle.HeightFactor();

	CFbsDrawDevice* drawDevice = iDevice->iDrawDevice;

	RShapeInfo shapeInfo;
	while (aParam.iPosInText < aEnd)
		{
		if (!iFont.GetCharacterPosition2(aParam, shapeInfo))
			continue;
		TInt adjustment = 0;
		if(iCharJustExcess && iCharJustNum > 0) // character clipping/justification
			{
			adjustment = CGraphicsContext::JustificationInPixels(iCharJustExcess,iCharJustNum);
			if(adjustment < 0)
				iClipRect.iBr.iX = Min(aParam.iPen.iX + adjustment,iClipRect.iBr.iX);
			}

		const CFont::TPositionParam::TOutput* output = aParam.iOutput;
		for (int i = 0; i < aParam.iOutputGlyphs; i++, output++)
			DoDrawCharacterLarge(output->iBounds.iTl,output->iBitmapSize,output->iBitmap,bold,italic,strikeheight,
								 widthfactor,heightfactor);

		iClipRect.iBr.iX = charclipping;
		if (adjustment)
			aParam.iPen.iX += adjustment;
		if (iWordJustExcess > 0 && iWordJustNum > 0 && aParam.iOutput[0].iCode == 0x0020) // word justification
			{
			adjustment = CGraphicsContext::JustificationInPixels(iWordJustExcess,iWordJustNum);
			aParam.iPen.iX += adjustment;
			}
		}
	if (shapeInfo.IsOpen())
		shapeInfo.Close();
	const TInt ulwidth = Max(font->CBitmapFont::DoHeightInPixels() / 10, 1);
	if (iUnderline == EUnderlineOn)
		{
		TInt ulstart = start_pen.iY + 1 + ulwidth / 2;
		TRect ul(start_pen.iX,ulstart,aParam.iPen.iX,ulstart + ulwidth);
		if(ul.Intersects(iClipRect)) // checks for empty aRect as well
			{
			ul.Intersection(iClipRect);
			drawDevice->WriteRgbMulti(ul.iTl.iX,ul.iTl.iY,ul.iBr.iX-ul.iTl.iX,ul.iBr.iY-ul.iTl.iY,iPenColor,iDrawMode);
			}
		}

	if (iStrikethrough == EStrikethroughOn)
		{
		TRect st(start_pen.iX,strikeheight,aParam.iPen.iX,strikeheight + ulwidth);
		if(st.Intersects(iClipRect)) // checks for empty aRect as well
			{
			st.Intersection(iClipRect);
			drawDevice->WriteRgbMulti(st.iTl.iX,st.iTl.iY,st.iBr.iX-st.iTl.iX,st.iBr.iY-st.iTl.iY,iPenColor,iDrawMode);
			}
		}
	}

void CFbsBitGc::DoDrawCharacterLarge(const TPoint& aTopLeft,const TSize& aDataSize,const TUint8* aData,
									 TBool aBold,TBool aItalic,TInt aSemiAscent,TInt aWidthFactor,TInt aHeightFactor)
	{
	TInt datalength = aDataSize.iWidth;
	TInt dataheight = aDataSize.iHeight;
	
	if (aWidthFactor > 2 || aHeightFactor > 2)
		{
		DoDrawCharacterMultiplied(aTopLeft,aDataSize,aData,aBold,aItalic,aSemiAscent,aWidthFactor,aHeightFactor);
		return;
		}
	
	if (datalength > 30 || dataheight > 32 || (aWidthFactor == 2 && datalength > 14))
		{
		DoDrawCharacterExLarge(aTopLeft,aDataSize,aData,aBold,aItalic,aSemiAscent,aWidthFactor,aHeightFactor);
		return;
		}
	
	TInt italicheight=aSemiAscent-aTopLeft.iY;
	if(aHeightFactor==2) italicheight>>=1;
	TInt bitindex=0;
	TInt16 repeatcount=0;
	TUint32 binarydata[64];
	TUint32* binarydataptr=binarydata;
	TUint32* binarydataptrlimit;

	for(TInt charline=0;charline<dataheight;charline+=repeatcount) // for lines in the character...
		{
		repeatcount=Load16(aData+(bitindex>>3));
		repeatcount>>=bitindex&7;
		TInt multilineflag=repeatcount&1;
		repeatcount>>=1;
		repeatcount&=0xf;
		bitindex+=5;
		binarydataptrlimit=binarydata+charline+repeatcount;
		if(multilineflag)
			{
			while(binarydataptr<binarydataptrlimit)
				{
				CopyCharWord(binarydataptr,aData+(bitindex>>3),bitindex&7);
				bitindex+=datalength;
				binarydataptr++;
				}
			}
		else
			{
			TUint32 data=0;
			CopyCharWord(&data,aData+(bitindex>>3),bitindex&7);
			while(binarydataptr<binarydataptrlimit)
				*binarydataptr++=data;
			bitindex+=datalength;
			}
		}
	binarydataptr=binarydata;
	binarydataptrlimit=binarydata+dataheight;
	if(aBold)
		{
		TInt sparemask=(0xffffffff>>(32-datalength));
		while(binarydataptr<binarydataptrlimit)
			{
			*binarydataptr&=sparemask;
			*binarydataptr|=(*binarydataptr<<1);
			++binarydataptr;
			}
		binarydataptr=binarydata;
		datalength++;
		}
	if(aItalic)
		{
		TUint32 sparemask=(0xffffffff>>(32-datalength));
		binarydataptrlimit=Min(binarydataptrlimit,binarydata+italicheight);
		while(binarydataptr<binarydataptrlimit)
			{
			*binarydataptr<<=1;
			*binarydataptr++&=0xfffffffe;
			}
		binarydataptrlimit=binarydata+dataheight;
		while(binarydataptr<binarydataptrlimit)
			*binarydataptr++&=sparemask;
		binarydataptr=binarydata;
		datalength++;
		}
	if(aWidthFactor==2)
		{
		BG_ASSERT_DEBUG(datalength<=16,EBitgdiPanicCharacterTooBig);
		while(binarydataptr<binarydataptrlimit)
			{
			TUint32 singlemask=0x8000;
			TUint32 doublemask=0xc0000000;
			TUint32 newdata=0;
			while(singlemask)
				{
				if(*binarydataptr&singlemask)
					newdata|=doublemask;
				singlemask>>=1;
				doublemask>>=2;
				}
			*binarydataptr++=newdata;
			}
		datalength<<=1;
		binarydataptr=binarydata;
		}
	if(aHeightFactor==2)
		{
		binarydataptr=binarydata+dataheight-1;
		TUint32* tempptr=binarydataptr+dataheight;
		while(binarydataptr>=binarydata)
			{
			*tempptr--=*binarydataptr;
			*tempptr--=*binarydataptr--;
			}
		dataheight<<=1;
		binarydataptr=binarydata;
		}
	TPoint startpos=aTopLeft;
	binarydataptr=ClipBinaryArray(binarydata,binarydata+dataheight,1,datalength,dataheight,startpos);
	if(datalength>0 && dataheight>0)
		iDevice->iDrawDevice->WriteBinary(startpos.iX,startpos.iY,binarydataptr,datalength,dataheight,iPenColor,iDrawMode);
	}

void CFbsBitGc::DoDrawCharacterExLarge(const TPoint& aTopLeft,const TSize& aDataSize,const TUint8* aData,
									   TBool aBold,TBool aItalic,TInt aSemiAscent,TInt aWidthFactor,TInt aHeightFactor)
	{
	CFbsDrawDevice* drawDevice = iDevice->iDrawDevice;
	TPoint printpos(aTopLeft);
	const TInt datalength = aDataSize.iWidth;
	const TInt dataheight = aDataSize.iHeight;
	TInt bitindex=0;
	TInt16 repeatcount=0;
	TUint32* slbuffer=drawDevice->ScanLineBuffer();
	const TInt slwords=(drawDevice->ScanLineBytes())<<3;
	if(aItalic && aTopLeft.iY<aSemiAscent)
		printpos.iX++;
	for(TInt charline=0;charline<dataheight;charline+=repeatcount) // for lines in the character...
		{
		repeatcount=Load16(aData+(bitindex>>3));
		repeatcount>>=bitindex&7;
		const TInt multilineflag=repeatcount&1;
		repeatcount>>=1;
		repeatcount&=0xf;
		bitindex+=5;
		if(multilineflag)
			{
			for(TInt currentline=0;currentline<repeatcount;currentline++)
				{
				CopyCharLine(slbuffer,slwords,aData+(bitindex>>3),bitindex&7,datalength);
				OutputCharLineMultiplied(printpos,slbuffer,datalength,1,aBold,aWidthFactor,aHeightFactor);
				bitindex+=datalength;
				printpos.iY++;
				if(printpos.iY==aSemiAscent && aItalic) printpos.iX--;
				if(aHeightFactor==2)
					{
					printpos.iY++;
					if(printpos.iY==aSemiAscent && aItalic) printpos.iX--;
					}
				}
			}
		else
			{
			if(aItalic)
				{
				for(TInt currentline=0;currentline<repeatcount;currentline++)
					{
					CopyCharLine(slbuffer,slwords,aData+(bitindex>>3),bitindex&7,datalength);
					OutputCharLineMultiplied(printpos,slbuffer,datalength,1,aBold,aWidthFactor,aHeightFactor);
					printpos.iY++;
					if(printpos.iY==aSemiAscent && aItalic) printpos.iX--;
					if(aHeightFactor==2)
						{
						printpos.iY++;
						if(printpos.iY==aSemiAscent && aItalic) printpos.iX--;
						}
					}
				}
			else
				{
				CopyCharLine(slbuffer,slwords,aData+(bitindex>>3),bitindex&7,datalength);
				OutputCharLineMultiplied(printpos,slbuffer,datalength,repeatcount,aBold,aWidthFactor,aHeightFactor);
				printpos.iY+=repeatcount;
				if(aHeightFactor==2) printpos.iY+=repeatcount;
				}
			bitindex+=datalength;
			}
		}
	}

void CFbsBitGc::DoDrawCharacterMultiplied(const TPoint& aTopLeft,const TSize& aDataSize,const TUint8* aData,
										  TBool aBold,TBool aItalic,TInt aSemiAscent,TInt aWidthFactor,TInt aHeightFactor)
	{
	CFbsDrawDevice* drawDevice = iDevice->iDrawDevice;
	TPoint printpos(aTopLeft);
	const TInt datalength = aDataSize.iWidth;
	const TInt dataheight = aDataSize.iHeight;
	TInt bitindex=0;
	TInt16 repeatcount=0;
	TUint32* slbuffer=drawDevice->ScanLineBuffer();
	const TInt slwords=(drawDevice->ScanLineBytes())<<3;
	if(aItalic && aTopLeft.iY<aSemiAscent)
		printpos.iX++;
	for(TInt charline=0;charline<dataheight;charline+=repeatcount) // for lines in the character...
		{
		repeatcount=Load16(aData+(bitindex>>3));
		repeatcount>>=bitindex&7;
		const TInt multilineflag=repeatcount&1;
		repeatcount>>=1;
		repeatcount&=0xf;
		bitindex+=5;
		if(multilineflag)
			{
			for(TInt currentline=0;currentline<repeatcount;currentline++)
				{
				CopyCharLine(slbuffer,slwords,aData+(bitindex>>3),bitindex&7,datalength);
				OutputCharLineMultiplied(printpos,slbuffer,datalength,1,aBold,aWidthFactor,aHeightFactor);
				bitindex+=datalength;
				TBool aboveitalicjump=EFalse;
				if(aItalic && printpos.iY<aSemiAscent) aboveitalicjump=ETrue;
				printpos.iY+=aHeightFactor;
				if(aboveitalicjump && printpos.iY>=aSemiAscent) printpos.iX-=aWidthFactor;
				}
			}
		else
			{
			if(aItalic)
				{
				for(TInt currentline=0;currentline<repeatcount;currentline++)
					{
					CopyCharLine(slbuffer,slwords,aData+(bitindex>>3),bitindex&7,datalength);
					OutputCharLineMultiplied(printpos,slbuffer,datalength,1,aBold,aWidthFactor,aHeightFactor);
					TBool aboveitalicjump=EFalse;
					if(printpos.iY<aSemiAscent) aboveitalicjump=ETrue;
					printpos.iY+=aHeightFactor;
					if(aboveitalicjump && printpos.iY>=aSemiAscent) printpos.iX-=aWidthFactor;
					}
				}
			else
				{
				CopyCharLine(slbuffer,slwords,aData+(bitindex>>3),bitindex&7,datalength);
				OutputCharLineMultiplied(printpos,slbuffer,datalength,repeatcount,aBold,aWidthFactor,aHeightFactor);
				printpos.iY+=repeatcount*aHeightFactor;
				}
			bitindex+=datalength;
			}
		}
	}

void CFbsBitGc::OutputCharLineMultiplied(TPoint aPrintPos,TUint32* aBuffer,TInt aDataLength,TInt aNum,TBool aBold,TInt aWidthFactor,TInt aHeightFactor)
	{
	if(aDataLength<=0) return;
	TInt bufferwords=(aDataLength+31)>>5;
	TUint32* bufferlimit=aBuffer+bufferwords;
	if(aBold)
		{
		TInt sparemask=(0xffffffff>>(32-(aDataLength&0x1f)));
		if((aDataLength&0x1f)==0) sparemask=0xffffffff;
		*(bufferlimit-1)&=sparemask;
		TUint32* bufferptr=aBuffer;
		TUint32 extrabit=0;
		while(bufferptr<bufferlimit)
			{
			extrabit=*bufferptr>>31;
			*bufferptr|=(*bufferptr<<1);
			++bufferptr;
			if(bufferptr<bufferlimit)
				*bufferptr|=extrabit;
			}
		aDataLength++;
		if((aDataLength&0x1f)==1)
			{
			bufferwords++;
			*bufferlimit=extrabit;
			bufferlimit++;
			}
		}
	if(aWidthFactor>1)
		{
		BitMultiply(aBuffer,aDataLength,aWidthFactor);
		aDataLength*=aWidthFactor;
		bufferwords=(aDataLength+31)>>5;
		bufferlimit=aBuffer+bufferwords;
		}
	if(aPrintPos.iX<iClipRect.iTl.iX)
		{
		TInt pixelexcess=iClipRect.iTl.iX-aPrintPos.iX;
		while(pixelexcess>=32)
			{
			aBuffer++;
			bufferwords--;
			aDataLength-=32;
			pixelexcess-=32;
			}
		if(aDataLength<=0) return;
		if(pixelexcess>0)
			{
			TInt shiftup=32-pixelexcess;
			TUint32* bufferptr=aBuffer;
			while(bufferptr<bufferlimit)
				{
				*bufferptr>>=pixelexcess;
				if(bufferptr<bufferlimit-1)
					*bufferptr|=(*(bufferptr+1)<<shiftup);
				bufferptr++;
				}
			aDataLength-=pixelexcess;
			if(aDataLength<=0) return;
			}
		aPrintPos.iX=iClipRect.iTl.iX;
		}
	if(aPrintPos.iX+aDataLength>iClipRect.iBr.iX)
		{
		TInt pixelexcess=aPrintPos.iX+aDataLength-iClipRect.iBr.iX;
		aDataLength-=pixelexcess;
		if(aDataLength<=0) return;
		}
	aNum*=aHeightFactor;
	while(aNum>0)
		{
		if(aPrintPos.iY>=iClipRect.iTl.iY && aPrintPos.iY<iClipRect.iBr.iY)
			iDevice->iDrawDevice->WriteBinaryLine(aPrintPos.iX,aPrintPos.iY,aBuffer,aDataLength,iPenColor,iDrawMode);
		aPrintPos.iY++;
		aNum--;
		}
	}

void CFbsBitGc::CopyCharWord(TUint32* aBinaryDataPtr,const TUint8* aData,TInt aBitShift)
	{
	const TUint32* dataword=(TUint32*)(TInt(aData)&~3);
	aBitShift+=(TInt(aData)-TInt(dataword))<<3;
	*aBinaryDataPtr=*dataword++;
	if(aBitShift<32) *aBinaryDataPtr>>=aBitShift;
	if(aBitShift) *aBinaryDataPtr|=(*dataword<<(32-aBitShift));
	}
	
void CFbsBitGc::CopyCharLine(TUint32* aBinaryDataPtr,TInt aBufferWords,const TUint8* aData,TInt aBitShift,TInt aCharWidth)
	{
	aBitShift&=7;
	TInt wordstocopy=(aCharWidth+31)>>5;
	if(wordstocopy>aBufferWords) wordstocopy=aBufferWords;
	TUint32* ptrlimit=aBinaryDataPtr+wordstocopy;
	TUint32* dataword=(TUint32*)(TInt(aData)&~3);
	aBitShift+=(TInt(aData)-TInt(dataword))<<3;
	while(aBinaryDataPtr<ptrlimit)
		{
		*aBinaryDataPtr=*dataword++;
		*aBinaryDataPtr>>=aBitShift;
		if(aBitShift) *aBinaryDataPtr|=(*dataword<<(32-aBitShift));
		aBinaryDataPtr++;
		}
	}
	
TUint32* CFbsBitGc::ClipBinaryArray(TUint32* aArray,TUint32* aArrayLimit,TInt aArrayWordWd,TInt& aDataWd,TInt& aDataHt,TPoint& aPos)
	{
	TUint32* arrayptr=aArray;
	TInt clipdiff=iClipRect.iTl.iX-aPos.iX;
	if(aArrayWordWd==1)
		{
		if(clipdiff>0)
			{
			while(arrayptr<aArrayLimit)
				*arrayptr++>>=clipdiff;
			aDataWd-=clipdiff;
			aPos.iX=iClipRect.iTl.iX;
			arrayptr=aArray;
			}
		if(aPos.iX+aDataWd>iClipRect.iBr.iX && aDataWd>0)
			aDataWd=iClipRect.iBr.iX-aPos.iX;
		clipdiff=iClipRect.iTl.iY-aPos.iY;
		if(clipdiff>0)
			{
			aDataHt-=clipdiff;
			arrayptr+=clipdiff;
			aPos.iY=iClipRect.iTl.iY;
			}
		if(aPos.iY+aDataHt>iClipRect.iBr.iY && aDataHt>0)
			aDataHt=iClipRect.iBr.iY-aPos.iY;
		}
	return(arrayptr);
	}

void CFbsBitGc::BitMultiply(TUint32* aBinaryDataPtr,TInt aBitLength,TInt aFactor)
	{
	TInt bitpos=aBitLength-1;
	TUint32* wordpos=aBinaryDataPtr+(bitpos>>5);
	TInt bitoffset=bitpos&0x1f;
	TInt multbitpos=(aBitLength*aFactor)-1;
	TUint32* multwordpos=aBinaryDataPtr+(multbitpos>>5);
	TInt multbitoffset=multbitpos&0x1f;
	while(bitpos>=0)
		{
		TUint32 bit=((*wordpos)>>bitoffset)&1;
		TInt next=multbitpos-aFactor;
		while(multbitpos>next)
			{
			if(bit) *multwordpos|=(1<<multbitoffset);
			else *multwordpos&=~(1<<multbitoffset);
			multbitpos--;
			multbitoffset--;
			if(multbitoffset<0)
				{
				multbitoffset=31;
				multwordpos--;
				}
			}
		bitpos--;
		bitoffset--;
		if(bitoffset<0)
			{
			bitoffset=31;
			wordpos--;
			}
		}
	}

void CFbsBitGc::GetStrikethroughMetrics(TInt& aTop,TInt& aBottom)
/** Get the top and bottom of a strikethrough line for the current font, relative to the baseline.*/
	{
	aTop = -(iFont.AscentInPixels() * 5/12) - 1;
	aBottom = aTop + Max(iFont.HeightInPixels() / 10,1);
	}

/** APIExtension can contain as many additional methods as is required by 
CGraphicsContext after its original conception. It takes 3 parameters.
Function is exported due to constrains of retaining BC with earlier versions.
This is not used directly by external methods, instead it is called by a named 
method in CGraphicsContext which passes the relivant arguements including an 
unique identifier for the required action.
@param aUid The unique identifier for the method that is required. Selected 
internally by a series of "if" statements. 
@see Valid Uid identifiers are listed in header gdi.h
@see CGraphicsContext
@param aOutput is a TAny pointer to a reference. Used to output data as the structure
does not need to be instantiated before the function call this adds greater 
flexibility.
@param aInput is a TAny pointer used to input data.
*/	
EXPORT_C TInt CFbsBitGc::APIExtension(TUid aUid, TAny*& aOutput, TAny* aInput)
	{
	if (aUid == KGetUnderlineMetrics)
		{		
		APIExGetUnderlineMetrics(aOutput);
		return KErrNone;	
		}
	else if (aUid == KSetShadowColor)
		{
		return APIExSetShadowColor(aInput);
		}
	else if (aUid == KGetShadowColor)
		{
		return APIExGetShadowColor(aOutput);
		}
	else if (aUid == KDrawTextInContextUid)
		{
		TDrawTextInContextInternal* contextParam = (TDrawTextInContextInternal*)aInput;
		DrawText(contextParam->iText, &contextParam->iParam, contextParam->iPosition);
		return KErrNone;
		}
	else if (aUid == KDrawBoxTextInContextUid)
		{
		TDrawTextInContextInternal* contextParam = (TDrawTextInContextInternal*)aInput;
		DrawText(contextParam->iText,&contextParam->iParam,contextParam->iBox,contextParam->iBaselineOffset,contextParam->iAlign,contextParam->iMargin);
		return KErrNone;
		}
	else if (aUid == KDrawTextInContextVerticalUid)
		{
		TDrawTextInContextInternal* contextParam = (TDrawTextInContextInternal*)aInput;
		DrawTextVertical(contextParam->iText, &contextParam->iParam, contextParam->iPosition,contextParam->iUp);
		return KErrNone;
		}
	else if (aUid == KDrawBoxTextInContextVerticalUid)
		{
		TDrawTextInContextInternal* contextParam = (TDrawTextInContextInternal*)aInput;
		DrawTextVertical(contextParam->iText,&contextParam->iParam,contextParam->iBox,contextParam->iBaselineOffset,contextParam->iUp,contextParam->iAlign,contextParam->iMargin);
		return KErrNone;
		}
	else if (aUid == KUidIsFbsBitmapGc)
		{
		return APIExIsFbsBitGc(aOutput);
		}
	/* Future cases may be placed here later.*/
	else
		return CBitmapContext::APIExtension(aUid, aOutput, aInput);
	}
	
	
	
	
		
	
	
	
	
//The methods listed above in APIExtension follow here with the prefix APIEx.
void CFbsBitGc::APIExGetUnderlineMetrics(TAny*& aOutput)
	{
	const TInt width = Max(iFont.HeightInPixels() / 10,1);
	TTwoTInt* ptr = (TTwoTInt*)aOutput;
	ptr->iTop = 1 + width / 2;
	ptr->iBottom = (ptr->iTop) + width;
	}

TInt CFbsBitGc::APIExSetShadowColor(TAny* aShadowColor)
	{
	iFbsBitGcExtraData->SetShadowColor(*(reinterpret_cast<TRgb*>(aShadowColor)));
	return KErrNone;
	}

TInt CFbsBitGc::APIExGetShadowColor(TAny*& aShadowColor)
	{
	TRgb* output = reinterpret_cast<TRgb*>(aShadowColor);
	*output = iFbsBitGcExtraData->ShadowColor();
	return KErrNone;
	}
	
TInt CFbsBitGc::APIExIsFbsBitGc(TAny*& aIsCFbsBitGc)
	{
	TBool *output = reinterpret_cast<TBool*>(aIsCFbsBitGc);
	*output = ETrue;
	return KErrNone;
	}

EXPORT_C void CFbsBitGc::DrawText(const TDesC& aText,const TTextParameters* aParam)
	{
	DrawText(aText,aParam,iLastPrintPosition,ELeft,CFont::EHorizontal);
	}

EXPORT_C void CFbsBitGc::DrawText(const TDesC& aText,const TTextParameters* aParam,const TPoint& aPosition)
	{
	DrawText(aText,aParam,aPosition,ELeft,CFont::EHorizontal);
	}
	
	
EXPORT_C void CFbsBitGc::DrawText(const TDesC& aText,const TTextParameters* aParam,const TRect& aBox)
	{
	TRect boxcpy(aBox);
	boxcpy.Move(iOrigin);
	if(!iUserClipRect.Intersects(boxcpy)) return;
	TRect oldcliprect(iUserClipRect);
	iUserClipRect.Intersection(boxcpy);
	DrawText(aText,aParam);
	iUserClipRect=oldcliprect;
	}
	
EXPORT_C void CFbsBitGc::DrawText(const TDesC& aText,const TTextParameters* aParam,const TRect& aBox,TInt aBaselineOffset,TTextAlign aHrz,TInt aMargin)
	{
	DrawText(aText,aParam,aBox,aBaselineOffset,-1,aHrz,aMargin);
	}
	
EXPORT_C void CFbsBitGc::DrawText(const TDesC& aText,const TTextParameters* aParam,const TRect& aBox,TInt aBaselineOffset,TInt /*aTextWidth*/,TTextAlign aHrz,TInt aMargin)
	{
	// aTextWidth is not used here - try to abolish this - I think it is unneeded
	TPoint p(aBox.iTl);
	p.iY += aBaselineOffset;
	switch (aHrz)
		{
		case ELeft: p.iX += aMargin; break;
		case ERight: p.iX = aBox.iBr.iX - aMargin; break;
		case ECenter: p.iX += aBox.Width() / 2 + aMargin; break;
		}
	DrawText(aText,aParam,p,aHrz,CFont::EHorizontal,&aBox);
	}