os/graphics/fbs/fontandbitmapserver/tfbs/tfbsglyphdata.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
sl@0
     1
// Copyright (c) 2009-2010 Nokia Corporation and/or its subsidiary(-ies).
sl@0
     2
// All rights reserved.
sl@0
     3
// This component and the accompanying materials are made available
sl@0
     4
// under the terms of "Eclipse Public License v1.0"
sl@0
     5
// which accompanies this distribution, and is available
sl@0
     6
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
sl@0
     7
//
sl@0
     8
// Initial Contributors:
sl@0
     9
// Nokia Corporation - initial contribution.
sl@0
    10
//
sl@0
    11
// Contributors:
sl@0
    12
//
sl@0
    13
// Description:
sl@0
    14
//
sl@0
    15
sl@0
    16
/**
sl@0
    17
 @file
sl@0
    18
 @internalComponent - Internal Symbian test code
sl@0
    19
*/
sl@0
    20
sl@0
    21
#include <test/graphicsfontutils.h>
sl@0
    22
#include <EGL/egl.h>
sl@0
    23
#include <VG/openvg.h>
sl@0
    24
#include <graphics/fbsglyphmetricsarray.h> 
sl@0
    25
#include <graphics/fbsglyphdataiterator.h>
sl@0
    26
#include <sgresource/sgimage.h>
sl@0
    27
#include <sgresource/sgdriver_test.h>
sl@0
    28
#include <sgresource/sgdriver_profiling.h>
sl@0
    29
#include "FbsMessage.h"
sl@0
    30
#include "tfbsglyphdata.h"
sl@0
    31
sl@0
    32
_LIT(KTypefaceName, "DejaVu Sans Condensed");
sl@0
    33
//_LIT(KMonoTypefaceName, "DejaVu Sans Mono");
sl@0
    34
const TInt KNumGlyphCodesLatin = 96;
sl@0
    35
const TUint KDejaVuInvalidGlyphCode = 0;
sl@0
    36
sl@0
    37
// Currently only used in debug. When TestMultithreadStressAtlas() test is enabled, #ifdef to be removed. 
sl@0
    38
#ifdef _DEBUG
sl@0
    39
const TInt KTestThreadMinHeapSize = 0x20000;
sl@0
    40
const TInt KTestThreadMaxHeapSize = 0x20000;
sl@0
    41
#endif
sl@0
    42
sl@0
    43
// 'most significant bit' flag to ensure value is interpreted as a glyph code rather than an ascii code
sl@0
    44
const TUint KGlyphCodeFlag = 0x80000000;      
sl@0
    45
sl@0
    46
sl@0
    47
// Please note the following macros which enable helper functions, and are declared in the header.
sl@0
    48
// SAVEGLYPHSTOMBMDURINGCOMPARISON and
sl@0
    49
// SAVEGLYPHSTOMBMDEBUGFUNCTION
sl@0
    50
sl@0
    51
// Utility function declarations - utilities used by the tests
sl@0
    52
static TFontSpec GenerateDejaVuFontSpec(TInt aSeed);
sl@0
    53
static void CopyCharLine(TUint32*& aBinaryDataPtr,TInt aBufferWords,const TUint8* aData,TInt aBitShift,TInt aCharWidth, TInt16 aRepeatCount);
sl@0
    54
static void DecodeBinaryData(const TSize& aDataSize, const TUint8* aData, TInt aStride,	TUint32* aBinaryData);
sl@0
    55
static TInt CreateSgImageFromCharacterData(const TUint8* aData, const TSize& aSize, TGlyphBitmapType aType, RSgImage& aImage);
sl@0
    56
static TInt CreateSgImageFromCharacterData(const TUint8* aData, const TSize& aSize, TGlyphBitmapType aType, RSgImage& aImage, TUint8* aBuffer1, TUint8* aBuffer2);
sl@0
    57
// Following functions commented out because the tests which use these functions 
sl@0
    58
// are currently commented out due to Broadcom defect 
sl@0
    59
// ESLM-85LDV7 - TB10.1 Closing of RSgImage with duplicate handle used in same thread does not release GPU RAM
sl@0
    60
//static TInt FillGraphicsMemoryWithImages(const TSize& aSize, RArray<RSgImage>& aImages);
sl@0
    61
//static TInt NearlyFillGraphicsMemoryWithImages(const TSize& aSize, RArray<RSgImage>& aImages);
sl@0
    62
sl@0
    63
#if defined (SAVEGLYPHSTOMBMDEBUGFUNCTION) || defined (SAVEGLYPHSTOMBMDURINGCOMPARISON)
sl@0
    64
/**
sl@0
    65
Static utility function. Converts an A8 RSgImage into a CFbsBitmap.
sl@0
    66
To do this, the RSgImage is converted to an EGLImage, then to a VGImage,
sl@0
    67
where the image memory is read into a CFbsBitmap.
sl@0
    68
sl@0
    69
@param aEGL The EGL helper object that will read the SgImage into a memory buffer.
sl@0
    70
@param aSgImage The RSgImage to convert.
sl@0
    71
@param aRect A rectangular region of the RSgImage to convert.
sl@0
    72
@param aBitmap On success, holds a pointer to a CFbsBitmap which contains the image
sl@0
    73
	data of the RSgImage.
sl@0
    74
@return One of the system-wide error codes.
sl@0
    75
*/
sl@0
    76
static TInt CreateBitmapFromSgImage(CEGLHelper* aEGL, const RSgImage& aSgImage, const TRect& aRect, CFbsBitmap*& aBitmap)
sl@0
    77
	{
sl@0
    78
	TInt err = KErrNone;
sl@0
    79
	const TSize bufferSize = aRect.Size();
sl@0
    80
	const TInt dataStride = bufferSize.iWidth;
sl@0
    81
sl@0
    82
	TUint8* imageBuffer = reinterpret_cast<TUint8*>(User::AllocZ(bufferSize.iHeight * dataStride));
sl@0
    83
	if (!imageBuffer)
sl@0
    84
		{
sl@0
    85
		return KErrNoMemory;
sl@0
    86
		}
sl@0
    87
	err = aEGL->GetSgImageData(aSgImage, aRect, imageBuffer);
sl@0
    88
	if (err != KErrNone)
sl@0
    89
		{
sl@0
    90
		User::Free(imageBuffer);
sl@0
    91
		return err;
sl@0
    92
		}
sl@0
    93
	aBitmap = new CFbsBitmap();
sl@0
    94
	if (!aBitmap)
sl@0
    95
		{
sl@0
    96
		User::Free(imageBuffer);
sl@0
    97
		return KErrNoMemory;
sl@0
    98
		}
sl@0
    99
sl@0
   100
	err = aBitmap->Create(bufferSize, EGray256);
sl@0
   101
	if (KErrNone == err)
sl@0
   102
		{
sl@0
   103
		TUint8* buf = imageBuffer;
sl@0
   104
		aBitmap->BeginDataAccess();
sl@0
   105
		TUint8* dataAddress = reinterpret_cast<TUint8*>(aBitmap->DataAddress());
sl@0
   106
		const TInt dataStride = aBitmap->DataStride();	
sl@0
   107
		for (TInt scanline = 0; scanline < bufferSize.iHeight; scanline++)
sl@0
   108
			{
sl@0
   109
			Mem::Copy(dataAddress, buf, bufferSize.iWidth);
sl@0
   110
			dataAddress += dataStride;
sl@0
   111
			buf += bufferSize.iWidth;
sl@0
   112
			}
sl@0
   113
		aBitmap->EndDataAccess(EFalse);
sl@0
   114
		}
sl@0
   115
	else
sl@0
   116
		{
sl@0
   117
		delete aBitmap;
sl@0
   118
		aBitmap = NULL;
sl@0
   119
		}
sl@0
   120
sl@0
   121
	User::Free(imageBuffer);
sl@0
   122
	return err;
sl@0
   123
	}
sl@0
   124
sl@0
   125
/**
sl@0
   126
Utility function to aid with debugging.
sl@0
   127
Saves a bitmap to file.
sl@0
   128
sl@0
   129
@param aBmp Bitmap to save
sl@0
   130
@param aMeta Optional. If specified, it is added to the name of the bitmap file.
sl@0
   131
@param aRef Flag to show whether bitmap is a reference bitmap (ETrue) or test bitmap (EFalse).
sl@0
   132
*/
sl@0
   133
static void SaveBmp(CFbsBitmap* aBmp, TPtrC* aMeta, TBool aRef)
sl@0
   134
	{
sl@0
   135
	if (!aBmp)
sl@0
   136
		{
sl@0
   137
		return;
sl@0
   138
		}
sl@0
   139
	
sl@0
   140
	TBuf<256> testFileName;
sl@0
   141
	if (aRef)
sl@0
   142
		{
sl@0
   143
		testFileName.Append(_L("Ref"));
sl@0
   144
		}
sl@0
   145
	else
sl@0
   146
		{
sl@0
   147
		testFileName.Append(_L("Test"));
sl@0
   148
		}
sl@0
   149
	if (aMeta)
sl@0
   150
		{
sl@0
   151
		testFileName.Append(*aMeta);
sl@0
   152
		}
sl@0
   153
sl@0
   154
	TFileName mbmFile;
sl@0
   155
	TBuf<20> testPathName;
sl@0
   156
	#ifdef __WINS__
sl@0
   157
		testPathName.Append(_L("c:\\%S.mbm"));
sl@0
   158
	#else
sl@0
   159
		testPathName.Append(_L("e:\\%S.mbm"));
sl@0
   160
	#endif
sl@0
   161
	mbmFile.Format(testPathName, &testFileName);
sl@0
   162
sl@0
   163
	// As this is for debugging purposes only, doesn't matter reporting whether
sl@0
   164
	// saving succeeded or not.
sl@0
   165
	aBmp->Save(mbmFile);
sl@0
   166
	}
sl@0
   167
#endif // SAVEGLYPHSTOMBMDEBUGFUNCTION OR SAVEGLYPHSTOMBMDURINGCOMPARISON
sl@0
   168
sl@0
   169
sl@0
   170
#ifdef SAVEGLYPHSTOMBMDEBUGFUNCTION
sl@0
   171
void CTFbsGlyphData::SaveRSgImagesAsMbms(CEGLHelper* aEGL, const RSgImage& aImageA, const TRect& aRectA, const RSgImage& aImageB, const TRect& aRectB )
sl@0
   172
	{
sl@0
   173
	static TInt countToAppend = 0;
sl@0
   174
sl@0
   175
	CFbsBitmap* bitmap = NULL;
sl@0
   176
	if (KErrNone == CreateBitmapFromSgImage(aEGL, aImageA, aRectA, bitmap))
sl@0
   177
		{
sl@0
   178
		TBuf<KMaxFileName> buf( _L("String") );
sl@0
   179
		buf.AppendNum( countToAppend );
sl@0
   180
		TPtrC nameAppend( buf );
sl@0
   181
sl@0
   182
		SaveBmp(bitmap, &nameAppend, EFalse);
sl@0
   183
		}
sl@0
   184
	delete bitmap;  
sl@0
   185
	bitmap = NULL;
sl@0
   186
sl@0
   187
	if (KErrNone == CreateBitmapFromSgImage(aEGL, aImageB, aRectB, bitmap))
sl@0
   188
		{
sl@0
   189
		TBuf<KMaxFileName> buf( _L("String") );
sl@0
   190
		buf.AppendNum( countToAppend );
sl@0
   191
		TPtrC nameAppend( buf );
sl@0
   192
sl@0
   193
		SaveBmp(bitmap, &nameAppend, ETrue);
sl@0
   194
		}
sl@0
   195
	delete bitmap;
sl@0
   196
	bitmap = NULL;
sl@0
   197
sl@0
   198
	countToAppend++;
sl@0
   199
	}
sl@0
   200
sl@0
   201
/**
sl@0
   202
Static debug utility method that outputs the glyph images of the given glyph
sl@0
   203
codes for the given font to a file.
sl@0
   204
 */
sl@0
   205
static void DumpFontGlyphs(CEGLHelper* aEGL, CFont* aFont, TInt aCodesCount)
sl@0
   206
	{
sl@0
   207
	TFontSpec fontSpec = aFont->FontSpecInTwips();
sl@0
   208
	TOpenFontCharMetrics charMetrics;
sl@0
   209
	TSize bitmapSize;
sl@0
   210
	const TUint8* bitmapData = NULL;
sl@0
   211
	
sl@0
   212
	for (TInt glyphCode = 0; glyphCode < aCodesCount; glyphCode++)
sl@0
   213
		{
sl@0
   214
		CFont::TCharacterDataAvailability availability = aFont->GetCharacterData(glyphCode | KGlyphCodeFlag, charMetrics, bitmapData, bitmapSize);
sl@0
   215
		if (availability == CFont::EAllCharacterData)
sl@0
   216
			{
sl@0
   217
			RSgImage characterDataImage;
sl@0
   218
			TInt err = CreateSgImageFromCharacterData(bitmapData, bitmapSize, fontSpec.iFontStyle.BitmapType(), characterDataImage);
sl@0
   219
			if (err == KErrNone)
sl@0
   220
				{
sl@0
   221
				CFbsBitmap* bitmap = NULL;
sl@0
   222
				err = CreateBitmapFromSgImage(aEGL, characterDataImage, TRect(TPoint(0, 0), bitmapSize), bitmap);
sl@0
   223
				if (err == KErrNone)
sl@0
   224
					{
sl@0
   225
					TBuf<256> bitmapName;
sl@0
   226
					bitmapName.AppendFormat(_L("%S-%i"), &(fontSpec.iTypeface.Name()), glyphCode);
sl@0
   227
					TPtrC bitmapNamePtr(bitmapName);
sl@0
   228
					SaveBmp(bitmap, &bitmapNamePtr, EFalse);
sl@0
   229
					delete bitmap;
sl@0
   230
					}
sl@0
   231
				}
sl@0
   232
			characterDataImage.Close();
sl@0
   233
			}
sl@0
   234
		}
sl@0
   235
	}
sl@0
   236
#endif // SAVEGLYPHSTOMBMDEBUGFUNCTION
sl@0
   237
sl@0
   238
sl@0
   239
/**
sl@0
   240
Utility to return a fontspec such that the font created from it will
sl@0
   241
not match any other font generated by a different seed. The font
sl@0
   242
will be useable by RFbsGlyphDataIterator and RFbsGlyphMetricsArray.
sl@0
   243
It will always return a font based on the DejaVu fontspec, this is 
sl@0
   244
so that the glyphcodes in DejaVuASCIIToGlyphCode are guaranteed to
sl@0
   245
work.
sl@0
   246
sl@0
   247
@param aSeed Specifies a variant of the fontspec to create. Passing the
sl@0
   248
	same seed will cause the same TFontSpec to be returned.
sl@0
   249
@return The generated fontspec. 
sl@0
   250
 */
sl@0
   251
static TFontSpec GenerateDejaVuFontSpec(TInt aSeed)
sl@0
   252
	{
sl@0
   253
	const TInt KFontHeightStep = 4;
sl@0
   254
	const TInt KFontInitialHeight = 8;
sl@0
   255
	
sl@0
   256
	const TInt KNumFontTypefaces = 3;
sl@0
   257
	const TInt KNumFontBitmapTypes = 2;
sl@0
   258
	const TInt KNumFontStyles = 4;
sl@0
   259
	
sl@0
   260
	TInt fontBitmapTypeVariant = aSeed % KNumFontBitmapTypes;
sl@0
   261
	TInt fontStyleVariant = (aSeed / KNumFontBitmapTypes) % KNumFontStyles;
sl@0
   262
	TInt fontTypefaceVariant = (aSeed / ( KNumFontStyles * KNumFontBitmapTypes)) % KNumFontTypefaces;
sl@0
   263
	TInt fontHeightVariant = aSeed / (KNumFontStyles * KNumFontTypefaces * KNumFontBitmapTypes);
sl@0
   264
	
sl@0
   265
	TFontSpec fontSpec;	
sl@0
   266
	fontSpec.iHeight = KFontInitialHeight + (fontHeightVariant * KFontHeightStep);
sl@0
   267
	// Set the typeface name
sl@0
   268
	// Set the style.
sl@0
   269
	switch (fontStyleVariant)
sl@0
   270
		{
sl@0
   271
		case 1: // italic
sl@0
   272
			fontSpec.iFontStyle.SetPosture(EPostureItalic);
sl@0
   273
			fontSpec.iFontStyle.SetStrokeWeight(EStrokeWeightNormal);
sl@0
   274
			break;
sl@0
   275
		case 2: // bold
sl@0
   276
			fontSpec.iFontStyle.SetPosture(EPostureUpright);
sl@0
   277
			fontSpec.iFontStyle.SetStrokeWeight(EStrokeWeightBold);
sl@0
   278
			break;
sl@0
   279
		case 3: // bold italic
sl@0
   280
			fontSpec.iFontStyle.SetPosture(EPostureItalic);
sl@0
   281
			fontSpec.iFontStyle.SetStrokeWeight(EStrokeWeightBold);
sl@0
   282
			break;
sl@0
   283
		default: // normal 
sl@0
   284
			fontSpec.iFontStyle.SetPosture(EPostureUpright);
sl@0
   285
			fontSpec.iFontStyle.SetStrokeWeight(EStrokeWeightNormal);
sl@0
   286
			break;
sl@0
   287
		}
sl@0
   288
	switch (fontTypefaceVariant)
sl@0
   289
		{
sl@0
   290
		case 1:
sl@0
   291
			fontSpec.iTypeface.SetName(_L("DejaVu Sans Mono"));
sl@0
   292
			break;
sl@0
   293
		case 2:
sl@0
   294
			fontSpec.iTypeface.SetName(_L("DejaVu Serif Condensed"));
sl@0
   295
			break;
sl@0
   296
		case 3:
sl@0
   297
			fontSpec.iTypeface.SetName(_L("DejaVu Sans Condensed"));
sl@0
   298
			break;
sl@0
   299
		}
sl@0
   300
	switch(fontBitmapTypeVariant)
sl@0
   301
		{
sl@0
   302
		case 1:
sl@0
   303
			fontSpec.iFontStyle.SetBitmapType(EMonochromeGlyphBitmap);
sl@0
   304
			break;
sl@0
   305
		default:
sl@0
   306
			fontSpec.iFontStyle.SetBitmapType(EAntiAliasedGlyphBitmap);
sl@0
   307
			break;
sl@0
   308
		}
sl@0
   309
sl@0
   310
	return fontSpec;
sl@0
   311
	}
sl@0
   312
sl@0
   313
sl@0
   314
/**
sl@0
   315
 * 
sl@0
   316
 EGL helper class to retrieve image data from an SgImage into a memory buffer.
sl@0
   317
 */
sl@0
   318
CEGLHelper::CEGLHelper() :
sl@0
   319
	iDisplay(EGL_NO_DISPLAY),
sl@0
   320
	iContext(EGL_NO_CONTEXT),
sl@0
   321
	iSurface(EGL_NO_SURFACE)
sl@0
   322
	{
sl@0
   323
	}
sl@0
   324
CEGLHelper::~CEGLHelper()
sl@0
   325
	{
sl@0
   326
	iMutex.Close();
sl@0
   327
	eglMakeCurrent(iDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
sl@0
   328
	eglDestroyContext(iDisplay, iContext);
sl@0
   329
	eglDestroySurface(iDisplay, iSurface);
sl@0
   330
	eglTerminate(iDisplay);
sl@0
   331
	eglReleaseThread();
sl@0
   332
	iSgDriver.Close();
sl@0
   333
	}
sl@0
   334
sl@0
   335
/**
sl@0
   336
Factory method to create CEGLHelper.
sl@0
   337
@return A pointer to an instance of CEGLHelper.
sl@0
   338
 */
sl@0
   339
CEGLHelper* CEGLHelper::NewL()
sl@0
   340
	{
sl@0
   341
	CEGLHelper* self = new CEGLHelper();
sl@0
   342
	CleanupStack::PushL(self);
sl@0
   343
	self->ConstructL();
sl@0
   344
	CleanupStack::Pop(1); // self
sl@0
   345
	return self;
sl@0
   346
	}
sl@0
   347
sl@0
   348
/**
sl@0
   349
Opens handle to the process-wide synchronisation semaphore,
sl@0
   350
loads EGL and VG extension function pointers,
sl@0
   351
sets up EGL resources so that EGLImages can be constructed. 
sl@0
   352
 */
sl@0
   353
void CEGLHelper::ConstructL()
sl@0
   354
	{
sl@0
   355
	_LIT(KEGLMutex, "TFbsGlyphDataEGLMutex");
sl@0
   356
	User::LeaveIfError(iMutex.CreateGlobal(KEGLMutex, EOwnerProcess));
sl@0
   357
	User::LeaveIfError(iSgDriver.Open());
sl@0
   358
sl@0
   359
	iDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
sl@0
   360
	if (iDisplay == EGL_NO_DISPLAY)
sl@0
   361
		{
sl@0
   362
		User::Leave(KErrNotSupported);
sl@0
   363
		}
sl@0
   364
	if (EGL_TRUE != eglInitialize(iDisplay, NULL, NULL))
sl@0
   365
		{
sl@0
   366
		User::Leave(KErrNotSupported);
sl@0
   367
		}
sl@0
   368
	eglBindAPI(EGL_OPENVG_API);
sl@0
   369
sl@0
   370
	// Load the necessary EGL extensions...
sl@0
   371
	eglCreateImageKHR = reinterpret_cast<PFNEGLCREATEIMAGEKHRPROC>(eglGetProcAddress("eglCreateImageKHR"));
sl@0
   372
	eglDestroyImageKHR = reinterpret_cast<PFNEGLDESTROYIMAGEKHRPROC>(eglGetProcAddress("eglDestroyImageKHR"));
sl@0
   373
	vgCreateImageTargetKHR = reinterpret_cast<TvgCreateEGLImageTargetKHRTypefPtr>(eglGetProcAddress("vgCreateEGLImageTargetKHR"));
sl@0
   374
	if (!eglCreateImageKHR || !eglDestroyImageKHR || !vgCreateImageTargetKHR)
sl@0
   375
		{
sl@0
   376
		User::Leave(KErrExtensionNotSupported);
sl@0
   377
		}
sl@0
   378
sl@0
   379
	// In order to create VGImages from EGLImages, a context must be current.
sl@0
   380
	// Therefore create an EGLContext and EGLSurface to make current, using
sl@0
   381
	// a dummy RSgImage.
sl@0
   382
sl@0
   383
	RSgImage dummySurface;
sl@0
   384
	TSgImageInfo dummySurfaceInfo(TSize(1, 1), ESgPixelFormatRGB_565, ESgUsageBitOpenVgSurface);
sl@0
   385
	User::LeaveIfError(dummySurface.Create(dummySurfaceInfo, NULL, 0));
sl@0
   386
	CleanupClosePushL(dummySurface);
sl@0
   387
sl@0
   388
	EGLint configAttribs[] = 
sl@0
   389
		{
sl@0
   390
		EGL_MATCH_NATIVE_PIXMAP, (EGLint)&dummySurface,
sl@0
   391
		EGL_RENDERABLE_TYPE, EGL_OPENVG_BIT,
sl@0
   392
		EGL_NONE
sl@0
   393
		};
sl@0
   394
sl@0
   395
	EGLint configId = 0;
sl@0
   396
	EGLint numConfigs = 0;
sl@0
   397
	if (EGL_FALSE == eglChooseConfig(iDisplay, configAttribs, &configId, 1, &numConfigs) || numConfigs == 0)
sl@0
   398
		{
sl@0
   399
		User::Leave(KErrGeneral);
sl@0
   400
		}
sl@0
   401
	iContext = eglCreateContext(iDisplay, configId, EGL_NO_CONTEXT, NULL);
sl@0
   402
	if (iContext == EGL_NO_CONTEXT)
sl@0
   403
		{
sl@0
   404
		User::Leave(KErrGeneral);
sl@0
   405
		}
sl@0
   406
	iSurface = eglCreatePixmapSurface(iDisplay, configId, &dummySurface, NULL);
sl@0
   407
	if (iSurface == EGL_NO_SURFACE)
sl@0
   408
		{
sl@0
   409
		User::Leave(KErrGeneral);
sl@0
   410
		}
sl@0
   411
	CleanupStack::PopAndDestroy(1); // dummySurface
sl@0
   412
	}
sl@0
   413
sl@0
   414
/**
sl@0
   415
Retrieves the data from an A8 RSgImage into a buffer.
sl@0
   416
To do this, the RSgImage is converted to an EGLImage, then to a VGImage,
sl@0
   417
where the image memory is read into the given buffer.
sl@0
   418
The function can be called from multiple threads and synchronisation
sl@0
   419
with EGL is controlled via a mutex.
sl@0
   420
sl@0
   421
@param aSgImage The RSgImage to convert.
sl@0
   422
@param aRect A rectangular region of the RSgImage to convert.
sl@0
   423
@param aBuf On success, contains the image data of the RSgImage.
sl@0
   424
@return One of the system-wide error codes.
sl@0
   425
 */
sl@0
   426
TInt CEGLHelper::GetSgImageData(const RSgImage& aSgImage, const TRect& aRect, TUint8*& aBuf)
sl@0
   427
	{
sl@0
   428
	const TSize bufferSize = aRect.Size();
sl@0
   429
	const TInt dataStride = bufferSize.iWidth;
sl@0
   430
sl@0
   431
	if (bufferSize == TSize(0,0))
sl@0
   432
		{
sl@0
   433
		return KErrNone;
sl@0
   434
		}
sl@0
   435
	iMutex.Wait();
sl@0
   436
sl@0
   437
	TInt err = KErrNone;
sl@0
   438
	EGLImageKHR eglImage;
sl@0
   439
	if (EGL_FALSE == eglBindAPI(EGL_OPENVG_API))
sl@0
   440
		{
sl@0
   441
		err = KErrGeneral;
sl@0
   442
		}
sl@0
   443
	else if (EGL_FALSE == eglMakeCurrent(iDisplay, iSurface, iSurface, iContext))
sl@0
   444
		{
sl@0
   445
		err = KErrGeneral;
sl@0
   446
		}
sl@0
   447
	else
sl@0
   448
		{
sl@0
   449
		// Create EGLImages from the RSgImage.
sl@0
   450
		EGLint imageAttribs[] =
sl@0
   451
			{
sl@0
   452
			EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, 
sl@0
   453
			EGL_NONE
sl@0
   454
			};
sl@0
   455
		eglImage = eglCreateImageKHR(iDisplay, EGL_NO_CONTEXT, EGL_NATIVE_PIXMAP_KHR, reinterpret_cast<EGLClientBuffer>(&aSgImage), imageAttribs);
sl@0
   456
		if (eglImage == EGL_NO_IMAGE_KHR)
sl@0
   457
			{
sl@0
   458
			err = KErrArgument;
sl@0
   459
			}
sl@0
   460
		}
sl@0
   461
	if (err == KErrNone)
sl@0
   462
		{
sl@0
   463
		// Create VGImages from the EGLImage.
sl@0
   464
		VGImage vgImage = vgCreateImageTargetKHR(eglImage);
sl@0
   465
		eglDestroyImageKHR(iDisplay, eglImage);
sl@0
   466
		if (vgImage == VG_INVALID_HANDLE)
sl@0
   467
			{
sl@0
   468
			err = KErrArgument;
sl@0
   469
			}
sl@0
   470
		else
sl@0
   471
			{
sl@0
   472
			// Get the image data in 8bpp format
sl@0
   473
			vgGetImageSubData(vgImage, aBuf, dataStride, VG_A_8, aRect.iTl.iX, aRect.iTl.iY, bufferSize.iWidth, bufferSize.iHeight);
sl@0
   474
			vgDestroyImage(vgImage);
sl@0
   475
			}
sl@0
   476
		}
sl@0
   477
	eglReleaseThread();
sl@0
   478
	iMutex.Signal();
sl@0
   479
	return err;
sl@0
   480
	}
sl@0
   481
sl@0
   482
CTFbsGlyphData::CTFbsGlyphData(CTestStep* aStep):
sl@0
   483
	CTGraphicsBase(aStep)
sl@0
   484
	{
sl@0
   485
	}
sl@0
   486
sl@0
   487
void CTFbsGlyphData::ConstructL()
sl@0
   488
	{
sl@0
   489
	User::LeaveIfError(Logger().ShareAuto());
sl@0
   490
	User::LeaveIfError(RFbsSession::Connect());
sl@0
   491
	iFbs = RFbsSession::GetSession();
sl@0
   492
	iTs = (CFbsTypefaceStore*)CFbsTypefaceStore::NewL(NULL);
sl@0
   493
	User::LeaveIfError(iTs->GetNearestFontToDesignHeightInPixels((CFont*&)iFont, TFontSpec(KTypefaceName, 15)));
sl@0
   494
	User::LeaveIfError(iTs->GetNearestFontToDesignHeightInPixels((CFont*&)iFont2, TFontSpec(KTypefaceName, 8)));
sl@0
   495
	
sl@0
   496
	CCharCodeConverter* converter = CCharCodeConverter::NewLC();
sl@0
   497
	converter->UseFontL(iFont);
sl@0
   498
	iGlyphCodesLatin = new(ELeave) TUint[KNumGlyphCodesLatin];
sl@0
   499
	for (TInt ii = 0; ii < KNumGlyphCodesLatin; ++ii)
sl@0
   500
		{
sl@0
   501
		TUint asciiCode = ii+0x20; // ASCII characters from 0020 to 007F
sl@0
   502
		iGlyphCodesLatin[ii] = converter->GlyphCodeL(asciiCode);
sl@0
   503
		}
sl@0
   504
	CleanupStack::PopAndDestroy(1); // converter
sl@0
   505
	
sl@0
   506
	User::LeaveIfError(iSgDriver.Open());
sl@0
   507
	iEGL = CEGLHelper::NewL();
sl@0
   508
	
sl@0
   509
	// Creating a CFbsBitmap will force the RFbsSession to allocate a scanline buffer
sl@0
   510
	// now rather than in the middle of a test, thus avoiding heap check failure. 
sl@0
   511
	CFbsBitmap* dummyBitmap = new (ELeave) CFbsBitmap;
sl@0
   512
	CleanupStack::PushL(dummyBitmap);
sl@0
   513
	User::LeaveIfError(dummyBitmap->Create(TSize(512, 1), EGray256));
sl@0
   514
	CleanupStack::PopAndDestroy(dummyBitmap);
sl@0
   515
sl@0
   516
	INFO_PRINTF1(_L("FBSERV Glyph Data Testing"));
sl@0
   517
	}
sl@0
   518
sl@0
   519
sl@0
   520
sl@0
   521
sl@0
   522
CTFbsGlyphData::~CTFbsGlyphData()
sl@0
   523
	{
sl@0
   524
	delete iEGL;
sl@0
   525
	iSgDriver.Close();
sl@0
   526
	if (iTs)
sl@0
   527
		{
sl@0
   528
		iTs->ReleaseFont(iFont);
sl@0
   529
		iTs->ReleaseFont(iFont2);
sl@0
   530
		}
sl@0
   531
	delete iTs;
sl@0
   532
	delete[] iGlyphCodesLatin;
sl@0
   533
	User::Free(iTempBuf1);
sl@0
   534
	User::Free(iTempBuf2);
sl@0
   535
	RFbsSession::Disconnect();
sl@0
   536
	}
sl@0
   537
sl@0
   538
void CTFbsGlyphData::RunTestCaseL(TInt aCurTestCase)
sl@0
   539
	{
sl@0
   540
	((CTFbsGlyphDataStep*)iStep)->SetTestStepID(KUnknownSYMTestCaseIDName);
sl@0
   541
	
sl@0
   542
	TRAPD(leave, 
sl@0
   543
sl@0
   544
	switch(aCurTestCase)
sl@0
   545
		{
sl@0
   546
	case 1:
sl@0
   547
		((CTFbsGlyphDataStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0624"));
sl@0
   548
		TestConsistencyWithGetCharacterData();
sl@0
   549
		break;
sl@0
   550
	case 2:
sl@0
   551
		((CTFbsGlyphDataStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0625"));
sl@0
   552
		TestInvalidGlyphCode();
sl@0
   553
		break;
sl@0
   554
	case 3:
sl@0
   555
		((CTFbsGlyphDataStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0626"));
sl@0
   556
		TestGlyphMetricsArrayParameters();
sl@0
   557
		break;
sl@0
   558
	case 4:
sl@0
   559
		((CTFbsGlyphDataStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0627"));
sl@0
   560
		TestGlyphMetricsArrayReuse();
sl@0
   561
		break;
sl@0
   562
	case 5:
sl@0
   563
		((CTFbsGlyphDataStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0628"));
sl@0
   564
		TestGlyphDataIteratorClose();
sl@0
   565
		break;
sl@0
   566
	case 6:
sl@0
   567
		((CTFbsGlyphDataStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0629"));
sl@0
   568
		TestGlyphDataIteratorSequence();
sl@0
   569
		break;	
sl@0
   570
	case 7:
sl@0
   571
		((CTFbsGlyphDataStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0632"));
sl@0
   572
		TestGlyphDataIteratorMultipleUsesOnMultipleFonts();
sl@0
   573
		break;
sl@0
   574
	case 8:
sl@0
   575
		((CTFbsGlyphDataStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0633"));
sl@0
   576
		TestGlyphDataIteratorImageValidity();
sl@0
   577
		break;
sl@0
   578
	case 9:
sl@0
   579
		((CTFbsGlyphDataStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0634"));
sl@0
   580
		TestGlyphDataIteratorOpenInvalidCode();
sl@0
   581
		break;
sl@0
   582
	case 10:
sl@0
   583
		((CTFbsGlyphDataStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0636"));
sl@0
   584
		TestGlyphDataIteratorOpenTwice();
sl@0
   585
		break;
sl@0
   586
	case 11:
sl@0
   587
		((CTFbsGlyphDataStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0637"));
sl@0
   588
		TestGlyphDataIteratorOpenTwiceWithDifferentFonts();
sl@0
   589
		break;
sl@0
   590
	case 12:
sl@0
   591
		((CTFbsGlyphDataStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0638"));
sl@0
   592
		TestGlyphDataIteratorOpenTooBigFont();
sl@0
   593
		break;
sl@0
   594
	case 13:
sl@0
   595
		((CTFbsGlyphDataStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0640"));
sl@0
   596
		TestGlyphDataIteratorOpenWithWrongArgument();
sl@0
   597
		break;
sl@0
   598
	case 14:
sl@0
   599
		((CTFbsGlyphDataStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0641"));
sl@0
   600
		TestGlyphDataIteratorImageMemoryLeak();
sl@0
   601
		break;
sl@0
   602
	case 15:
sl@0
   603
		((CTFbsGlyphDataStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0662"));
sl@0
   604
		TestGlyphDataIteratorNoGraphicsMemory();
sl@0
   605
		break;
sl@0
   606
	case 16: 
sl@0
   607
		((CTFbsGlyphDataStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0659"));
sl@0
   608
		TestGlyphDataIteratorLargeFontStress();
sl@0
   609
		break;
sl@0
   610
	case 17: 
sl@0
   611
		((CTFbsGlyphDataStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0660"));
sl@0
   612
		TestGlyphDataIteratorManyFontsStressL();
sl@0
   613
		break;
sl@0
   614
	case 18:
sl@0
   615
		((CTFbsGlyphDataStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0666"));
sl@0
   616
		TestGlyphDataIteratorNextIsAtomic();
sl@0
   617
		break;
sl@0
   618
	case 19:
sl@0
   619
		((CTFbsGlyphDataStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0665"));
sl@0
   620
		TestGlyphDataIteratorSameGlyphCodes();
sl@0
   621
		break;
sl@0
   622
	case 20:
sl@0
   623
		((CTFbsGlyphDataStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0668"));
sl@0
   624
		TestGlyphDataIteratorManyArraySizes();
sl@0
   625
		break;
sl@0
   626
	case 21:
sl@0
   627
		((CTFbsGlyphDataStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0669"));
sl@0
   628
		TestBitmapFontSupport();
sl@0
   629
		break;
sl@0
   630
	case 22:
sl@0
   631
		((CTFbsGlyphDataStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0671"));
sl@0
   632
		TestMultithreadShareSingleFont();
sl@0
   633
		break;
sl@0
   634
	case 23:
sl@0
   635
		((CTFbsGlyphDataStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0672"));
sl@0
   636
		TestMultithreadStressAtlas();
sl@0
   637
		break;
sl@0
   638
    case 24:
sl@0
   639
        ((CTFbsGlyphDataStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0673"));
sl@0
   640
        TestGlyphMetricsArrayHeapOOML();
sl@0
   641
        break;
sl@0
   642
    case 25:
sl@0
   643
        ((CTFbsGlyphDataStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0674"));
sl@0
   644
        TestGlyphDataIteratorHeapOOML();
sl@0
   645
        break;
sl@0
   646
	default:
sl@0
   647
		((CTFbsGlyphDataStep*)iStep)->SetTestStepID(KNotATestSYMTestCaseIDName);
sl@0
   648
		((CTFbsGlyphDataStep*)iStep)->CloseTMSGraphicsStep();
sl@0
   649
		TestComplete();
sl@0
   650
		break;
sl@0
   651
		}
sl@0
   652
	
sl@0
   653
	); // TRAPD
sl@0
   654
sl@0
   655
	if (leave != KErrNone)
sl@0
   656
		{
sl@0
   657
		ERR_PRINTF2(_L("Leave %d occurred during test"), leave);
sl@0
   658
		iStep->SetTestStepResult(EFail);
sl@0
   659
		}
sl@0
   660
sl@0
   661
	((CTFbsGlyphDataStep*)iStep)->RecordTestResultL();
sl@0
   662
	}
sl@0
   663
sl@0
   664
sl@0
   665
/**
sl@0
   666
@SYMTestCaseID		GRAPHICS-FBSERV-0624
sl@0
   667
@SYMTestPriority	High
sl@0
   668
@SYMTestType		UT
sl@0
   669
@SYMTestStatus		Implemented
sl@0
   670
@SYMPREQ			PREQ2678
sl@0
   671
sl@0
   672
@SYMTestCaseDesc
sl@0
   673
	Shows that RFbsGlyphMetricsArray::Get() and CFont::GetCharacterData() all 
sl@0
   674
	provide the same metrics for the same set of glyph codes when using a CFbsFont.
sl@0
   675
	Shows that RFbsGlyphDataIterator::Metrics() and CFont::GetCharacterData()
sl@0
   676
	provide the same metrics for the same set of glyph codes.
sl@0
   677
sl@0
   678
@SYMTestActions
sl@0
   679
	i. Call RFbsGlyphMetricsArray::Get() for a set of glyph codes with 1 glyph code per call.
sl@0
   680
	ii. Call RFbsGlyphMetricsArray::Get() for a set of glyph codes all in 1 call.
sl@0
   681
	iii. Call RFbsGlyphDataIterator::Open() for a set of glyph codes.
sl@0
   682
	iv. Call CFont::GetCharacterData() for the same set of glyph codes.
sl@0
   683
	v. Compare the metrics for each glyph code from all calls.
sl@0
   684
sl@0
   685
@SYMTestExpectedResults
sl@0
   686
	For each glyph code, metrics received from RFbsGlyphMetricsArray::Get() and
sl@0
   687
	CFont::GetCharacterData() and RFbsGlyphDataIterator are all the same.
sl@0
   688
*/
sl@0
   689
void CTFbsGlyphData::TestConsistencyWithGetCharacterData()
sl@0
   690
	{
sl@0
   691
	INFO_PRINTF1(_L("Test RFbsGlyphMetricsArray::Get() with GetCharacterData()"));
sl@0
   692
	
sl@0
   693
	__UHEAP_MARK;
sl@0
   694
sl@0
   695
	RFbsGlyphDataIterator iter;
sl@0
   696
	RFbsGlyphMetricsArray glyphMetricsArray;
sl@0
   697
	RFbsGlyphMetricsArray glyphMetricsArraySingle;
sl@0
   698
	
sl@0
   699
	TInt numMismatches = 0;
sl@0
   700
	TOpenFontCharMetrics charMetrics;
sl@0
   701
	TSize bitmapSize;
sl@0
   702
	const TUint8* bitmapData = NULL;
sl@0
   703
	
sl@0
   704
	// Retrieve list of metrics for all glyph codes in one call
sl@0
   705
	TInt err = glyphMetricsArray.Get(*iFont, iGlyphCodesLatin, KNumGlyphCodesLatin);
sl@0
   706
	TESTNOERROR(err);
sl@0
   707
	if (err == KErrNone)
sl@0
   708
		{
sl@0
   709
		TEST(KNumGlyphCodesLatin == glyphMetricsArray.Count());
sl@0
   710
		
sl@0
   711
		TInt index = 0;
sl@0
   712
		TInt iterErr = iter.Open(*iFont, iGlyphCodesLatin, KNumGlyphCodesLatin);
sl@0
   713
		TESTNOERROR(iterErr);
sl@0
   714
		for (; iterErr == KErrNone; iterErr = iter.Next(), index++)
sl@0
   715
			{
sl@0
   716
			iFont->GetCharacterData(iGlyphCodesLatin[index] | KGlyphCodeFlag, charMetrics, bitmapData, bitmapSize);
sl@0
   717
			
sl@0
   718
			// Retrieve the metrics for each glyph code, one at a time
sl@0
   719
			TESTNOERROR(err = glyphMetricsArraySingle.Get(*iFont, &iGlyphCodesLatin[index], 1));
sl@0
   720
			if (KErrNone == err)
sl@0
   721
				{
sl@0
   722
				// Compare GetCharacterData() metrics with single RFbsGlyphMetricsArray.
sl@0
   723
				TUint32 comparison1 = CompareMetrics(charMetrics, glyphMetricsArraySingle[0]); 
sl@0
   724
				// Compare GetCharacterData() metrics with large RFbsGlyphMetricsArray.
sl@0
   725
				TUint32 comparison2 = CompareMetrics(charMetrics, glyphMetricsArray[index]);
sl@0
   726
				// Compare GetCharacterData() metrics with RFbsGlyphDataIterator.
sl@0
   727
				TUint32 comparison3 = CompareMetrics(charMetrics, iter.Metrics());
sl@0
   728
				if (comparison1 != 0 || comparison2 != 0 || comparison3 != 0)
sl@0
   729
					{
sl@0
   730
					ERR_PRINTF5(_L("Glyphcode %i : Metrics mismatch: %d/%d/%d"), iGlyphCodesLatin[index], comparison1, comparison2, comparison3);
sl@0
   731
					++numMismatches;
sl@0
   732
					}
sl@0
   733
				}
sl@0
   734
			}
sl@0
   735
			iter.Close();
sl@0
   736
			glyphMetricsArray.Close();
sl@0
   737
			glyphMetricsArraySingle.Close();
sl@0
   738
			TESTE(iterErr == KErrNotFound, iterErr);
sl@0
   739
			TEST(numMismatches == 0);
sl@0
   740
			TEST(index == KNumGlyphCodesLatin);
sl@0
   741
		}		
sl@0
   742
	
sl@0
   743
	__UHEAP_MARKEND;
sl@0
   744
	}
sl@0
   745
sl@0
   746
/**
sl@0
   747
@return A series of success/fail booleans as a bitmask. A return value of zero
sl@0
   748
	indicates all tests passed, a result of 1 indicates the first test case failed, 
sl@0
   749
	a return of 3 indicates the first and second test failed, and so on.
sl@0
   750
*/
sl@0
   751
TUint32 CTFbsGlyphData::CompareMetrics(const TOpenFontCharMetrics& aMetrics1, const TOpenFontCharMetrics& aMetrics2)
sl@0
   752
	{
sl@0
   753
	TUint32 result = 0;
sl@0
   754
	result |= (aMetrics1.Width() == aMetrics2.Width()) ? 0 : (1 << 0);
sl@0
   755
	result |= (aMetrics1.Height() == aMetrics2.Height()) ? 0 : (1 << 1);
sl@0
   756
	result |= (aMetrics1.HorizBearingX() == aMetrics2.HorizBearingX()) ? 0 : (1 << 2);
sl@0
   757
	result |= (aMetrics1.HorizBearingY() == aMetrics2.HorizBearingY()) ? 0 : (1 << 3);
sl@0
   758
	result |= (aMetrics1.HorizAdvance() == aMetrics2.HorizAdvance()) ? 0 : (1 << 4);
sl@0
   759
	result |= (aMetrics1.VertBearingX() == aMetrics2.VertBearingX()) ? 0 : (1 << 5);
sl@0
   760
	result |= (aMetrics1.VertBearingY() == aMetrics2.VertBearingY()) ? 0 : (1 << 6);
sl@0
   761
	result |= (aMetrics1.VertAdvance() == aMetrics2.VertAdvance()) ? 0 : (1 << 7);
sl@0
   762
	TRect rect1;
sl@0
   763
	aMetrics1.GetHorizBounds(rect1);
sl@0
   764
	TRect rect2;
sl@0
   765
	aMetrics2.GetHorizBounds(rect2);
sl@0
   766
	result |= (rect1 == rect2) ? 0 : (1 << 8);
sl@0
   767
	aMetrics1.GetVertBounds(rect1);
sl@0
   768
	aMetrics2.GetVertBounds(rect2);
sl@0
   769
	result |= (rect1 == rect2) ? 0 : (1 << 9);
sl@0
   770
	return result;
sl@0
   771
	}
sl@0
   772
sl@0
   773
sl@0
   774
/**
sl@0
   775
@SYMTestCaseID		GRAPHICS-FBSERV-0625
sl@0
   776
@SYMTestPriority	High
sl@0
   777
@SYMTestType		UT
sl@0
   778
@SYMTestStatus		Implemented
sl@0
   779
@SYMPREQ			PREQ2678
sl@0
   780
sl@0
   781
@SYMTestCaseDesc
sl@0
   782
	Shows that RFbsGlyphMetricsArray::Get(), and CFont::GetCharacterData() show the same 
sl@0
   783
	behaviour when asked for metrics for an invalid glyph code when using a	CFbsFont. 
sl@0
   784
	An invalid glyph code is one for which there is no character equivalent, such as 
sl@0
   785
	0.
sl@0
   786
sl@0
   787
@SYMTestActions
sl@0
   788
	i. Call CFont::GetCharacterData() for an invalid glyph code.
sl@0
   789
	ii. Call RFbsGlyphMetricsArray::Get() for the same invalid glyph code, and either 
sl@0
   790
		compare the metrics if i. was successful, or check an error code was returned
sl@0
   791
	
sl@0
   792
@SYMTestExpectedResults
sl@0
   793
	If GetCharacterData() is successful, the metrics received from
sl@0
   794
	RFbsGlyphMetricsArray::Get() and CFont::GetCharacterData()	are the same, otherwise
sl@0
   795
	RFbsGlyphMetricsArray::Get() should return an error code.
sl@0
   796
*/
sl@0
   797
sl@0
   798
void CTFbsGlyphData::TestInvalidGlyphCode()
sl@0
   799
	{
sl@0
   800
	INFO_PRINTF1(_L("Test behaviour of RFbsGlyphMetricsArray::Get() with invalid glyph code is consistent with GetCharacterData"));
sl@0
   801
	
sl@0
   802
	__UHEAP_MARK;
sl@0
   803
	TInt arrayErr = KErrNone;
sl@0
   804
	RFbsGlyphMetricsArray glyphMetricsArray;
sl@0
   805
	TOpenFontCharMetrics charMetrics;
sl@0
   806
	TSize bitmapSize;
sl@0
   807
	const TUint8* bitmapData = NULL;
sl@0
   808
	
sl@0
   809
	CFont::TCharacterDataAvailability availability = iFont->GetCharacterData(KDejaVuInvalidGlyphCode | KGlyphCodeFlag, charMetrics, bitmapData, bitmapSize);
sl@0
   810
	if (availability == CFont::ENoCharacterData)
sl@0
   811
		{
sl@0
   812
		// Some rasterizers fail to return any data for KDejaVuInvalidGlyphCode, therefore
sl@0
   813
		// rather than compare metrics, make sure RFbsGlyphDataIterator returns an error code.
sl@0
   814
		WARN_PRINTF1(_L("Rasterizer failed to return data for invalid glyph code; not comparing glyph metrics"));
sl@0
   815
		arrayErr = glyphMetricsArray.Get(*iFont, &KDejaVuInvalidGlyphCode, 1);
sl@0
   816
		TESTE(arrayErr != KErrNone, arrayErr);
sl@0
   817
		}
sl@0
   818
	else
sl@0
   819
		{
sl@0
   820
		TESTNOERROR(arrayErr = glyphMetricsArray.Get(*iFont, &KDejaVuInvalidGlyphCode, 1));
sl@0
   821
		if (KErrNone == arrayErr)
sl@0
   822
			{
sl@0
   823
			iFont->GetCharacterData(KDejaVuInvalidGlyphCode | KGlyphCodeFlag, charMetrics, bitmapData, bitmapSize);
sl@0
   824
			TUint comparisonResult = CompareMetrics(charMetrics, glyphMetricsArray[0]);
sl@0
   825
			TESTNOERROR( comparisonResult );
sl@0
   826
			}
sl@0
   827
		}
sl@0
   828
	glyphMetricsArray.Close();
sl@0
   829
sl@0
   830
	__UHEAP_MARKEND;
sl@0
   831
	}
sl@0
   832
sl@0
   833
/**
sl@0
   834
@SYMTestCaseID		GRAPHICS-FBSERV-0626
sl@0
   835
@SYMTestPriority	High
sl@0
   836
@SYMTestType		UT
sl@0
   837
@SYMTestStatus		Implemented
sl@0
   838
@SYMPREQ			PREQ2678
sl@0
   839
sl@0
   840
@SYMTestCaseDesc
sl@0
   841
	Shows that RFbsGlyphMetricsArray::Get() returns with the correct error code when passed
sl@0
   842
	various combinations of parameters, and preserves the state of the array.
sl@0
   843
sl@0
   844
@SYMTestActions
sl@0
   845
	Populate the array with a single metrics entry.
sl@0
   846
	Call RFbsGlyphMetricsArray::Get with the following parameter combinations:
sl@0
   847
		1. A negative count
sl@0
   848
		2. A positive count and null glyph code array pointer
sl@0
   849
		3. A zero count and non-null glyph code array pointer
sl@0
   850
		4. A zero count and null glyph code array pointer
sl@0
   851
sl@0
   852
@SYMTestExpectedResults
sl@0
   853
	The following return codes are expected for each call:
sl@0
   854
		1. KErrArgument
sl@0
   855
		2. KErrArgument
sl@0
   856
		3. KErrArgument
sl@0
   857
		4. KErrArgument	
sl@0
   858
	For each case the glyph metrics array remains unchanged.
sl@0
   859
*/
sl@0
   860
void CTFbsGlyphData::TestGlyphMetricsArrayParameters()
sl@0
   861
	{
sl@0
   862
	INFO_PRINTF1(_L("Test the return values of GetGlyphMetrics with different parameters"));
sl@0
   863
	__UHEAP_MARK;
sl@0
   864
	TInt arrayErr = KErrNone;
sl@0
   865
	TOpenFontCharMetrics dummyMetrics;
sl@0
   866
	
sl@0
   867
	RFbsGlyphMetricsArray glyphMetricsArray;
sl@0
   868
	arrayErr = glyphMetricsArray.Get(*iFont, iGlyphCodesLatin, 1);
sl@0
   869
	TESTNOERROR(arrayErr);
sl@0
   870
	TEST(1 == glyphMetricsArray.Count());
sl@0
   871
	
sl@0
   872
	// 1. Negative Count
sl@0
   873
	arrayErr = glyphMetricsArray.Get(*iFont, iGlyphCodesLatin, -1);
sl@0
   874
	TESTE(KErrArgument == arrayErr, arrayErr);
sl@0
   875
	TEST(1 == glyphMetricsArray.Count());
sl@0
   876
	
sl@0
   877
	// 2. Positive Count and NULL Array Pointer
sl@0
   878
	arrayErr = glyphMetricsArray.Get(*iFont, NULL, 1);
sl@0
   879
	TESTE(KErrArgument == arrayErr, arrayErr);
sl@0
   880
	TEST(1 == glyphMetricsArray.Count());
sl@0
   881
sl@0
   882
	// 3. Zero Count & Valid Array Pointer
sl@0
   883
	arrayErr = glyphMetricsArray.Get(*iFont, iGlyphCodesLatin, 0);
sl@0
   884
	TESTE(KErrArgument == arrayErr, arrayErr);
sl@0
   885
sl@0
   886
	// 4. Zero Count & NULL Array Pointer
sl@0
   887
	arrayErr = glyphMetricsArray.Get(*iFont, NULL, 0);
sl@0
   888
	TESTE(KErrArgument == arrayErr, arrayErr);
sl@0
   889
sl@0
   890
	glyphMetricsArray.Close();
sl@0
   891
	__UHEAP_MARKEND;
sl@0
   892
	}
sl@0
   893
sl@0
   894
/**
sl@0
   895
@SYMTestCaseID		GRAPHICS-FBSERV-0627
sl@0
   896
@SYMTestPriority	High
sl@0
   897
@SYMTestType		UT
sl@0
   898
@SYMTestStatus		Implemented
sl@0
   899
@SYMPREQ			PREQ2678
sl@0
   900
sl@0
   901
@SYMTestCaseDesc
sl@0
   902
	Shows that reusing an RFbsGlyphMetricsArray works correctly.
sl@0
   903
	In particular when the array is reused and filled with fewer entries
sl@0
   904
	and when the array is reused and filled with more entries than previously.
sl@0
   905
	It also shows that when re-using an array that has been populated, memory 
sl@0
   906
	is not de-allocated if the new array of glyphs is smaller.
sl@0
   907
sl@0
   908
@SYMTestActions
sl@0
   909
	i. Call RFbsGlyphMetricsArray::Get() for a set of 10 glyph codes.
sl@0
   910
	ii. Check that the RFbsGlyphMetricsArray has 10 entries.
sl@0
   911
	iii. Find the size of the heap-cell allocated to the array.
sl@0
   912
	iii. Call RFbsGlyphMetricsArray::Get() for a set of 5 glyph codes.
sl@0
   913
	iv. Check that the RFbsGlyphMetricsArray has 5 entries.
sl@0
   914
	v. Call RFbsGlyphMetricsArray::Get() for a set of 20 glyph codes.
sl@0
   915
	vi. Check that the RFbsGlyphMetricsArray has 20 entries.
sl@0
   916
	vii. Call RFbsGlyphMetricsArray::Get() for a set of 0 glyph codes.
sl@0
   917
	viii. Check that the RFbsGlyphMetricsArray has 0 entries.
sl@0
   918
	ix. Call RFbsGlyphMetricsArray::Get() for 1 glyph code.
sl@0
   919
	x. Check that the RFbsGlyphMetricsArray has 1 entries.
sl@0
   920
	xi. Close the RFbsGlyphMetricsArray.
sl@0
   921
	xii. Check that the RFbsGlyphMetricsArray has 0 entries.
sl@0
   922
	During the test check that the size of the heap cell allocated to the array
sl@0
   923
	does not shrink.
sl@0
   924
sl@0
   925
@SYMTestExpectedResults
sl@0
   926
	After each call to RFbsGlyphMetricsArray::Get(), the array has the expected number of entries.
sl@0
   927
*/
sl@0
   928
void CTFbsGlyphData::TestGlyphMetricsArrayReuse()
sl@0
   929
	{
sl@0
   930
	INFO_PRINTF1(_L("Test reuse of array with RFbsGlyphMetricsArray"));
sl@0
   931
	__UHEAP_MARK;
sl@0
   932
	
sl@0
   933
	RFbsGlyphMetricsArray glyphMetricsArray;
sl@0
   934
sl@0
   935
	// Retrieve list of metrics for 10 glyph codes
sl@0
   936
	TESTNOERROR(glyphMetricsArray.Get(*iFont, iGlyphCodesLatin, 10));
sl@0
   937
	TEST(10 == glyphMetricsArray.Count());
sl@0
   938
	
sl@0
   939
	// Find the size of the heap cell allocated for the array.
sl@0
   940
	TInt arrayHeapCellSize = User::Heap().AllocLen(&glyphMetricsArray[0]);
sl@0
   941
	
sl@0
   942
	// Retrieve list of metrics for 5 glyph codes.
sl@0
   943
	// To ensure that different metrics are returned, use different glyph codes
sl@0
   944
	TESTNOERROR(glyphMetricsArray.Get(*iFont, &iGlyphCodesLatin[10], 5));
sl@0
   945
	TEST(5 == glyphMetricsArray.Count());
sl@0
   946
	// Check that memory has not been de-allocated for a smaller array.
sl@0
   947
	TEST(User::Heap().AllocLen(&glyphMetricsArray[0]) == arrayHeapCellSize);
sl@0
   948
sl@0
   949
	// Retrieve list of metrics for 20 glyph codes.
sl@0
   950
	// To ensure that different metrics are returned, use different glyph codes
sl@0
   951
	TESTNOERROR(glyphMetricsArray.Get(*iFont, &iGlyphCodesLatin[15], 20));
sl@0
   952
	TEST(20 == glyphMetricsArray.Count());
sl@0
   953
	arrayHeapCellSize = User::Heap().AllocLen(&glyphMetricsArray[0]);
sl@0
   954
		
sl@0
   955
	// Retrieve list of metrics for 0 glyph codes.
sl@0
   956
	TEST(KErrArgument == glyphMetricsArray.Get(*iFont, &iGlyphCodesLatin[35], 0));
sl@0
   957
	// We can't check whether memory has been de-allocated as glyphMetricsArray[0]
sl@0
   958
	// is null, therefore dereferencing it causes a panic.
sl@0
   959
sl@0
   960
	// Retrieve list of metrics for 1 glyph code.
sl@0
   961
	// To ensure that different metrics are returned, use different glyph code
sl@0
   962
	TESTNOERROR(glyphMetricsArray.Get(*iFont, &iGlyphCodesLatin[35], 1));
sl@0
   963
	TEST(1 == glyphMetricsArray.Count());
sl@0
   964
	TEST(User::Heap().AllocLen(&glyphMetricsArray[0]) == arrayHeapCellSize);
sl@0
   965
	
sl@0
   966
	// Test that after closing a non-empty array, the array has 0 size.
sl@0
   967
	glyphMetricsArray.Close();
sl@0
   968
	TEST(0 == glyphMetricsArray.Count());
sl@0
   969
	
sl@0
   970
	__UHEAP_MARKEND;
sl@0
   971
	}
sl@0
   972
sl@0
   973
/**
sl@0
   974
@SYMTestCaseID		GRAPHICS-FBSERV-0628
sl@0
   975
@SYMTestPriority	High
sl@0
   976
@SYMTestType		UT
sl@0
   977
@SYMTestStatus		Implemented
sl@0
   978
@SYMPREQ			PREQ2678
sl@0
   979
sl@0
   980
@SYMTestCaseDesc
sl@0
   981
	Validates the behaviour of RFbsGlyphDataIterator::Close() in the following use cases:
sl@0
   982
		1. When called on an iterator instance which has not been opened, has no effect.
sl@0
   983
		2. When called on an open iterator closes the iterator 
sl@0
   984
sl@0
   985
@SYMTestActions
sl@0
   986
	Use case 1:
sl@0
   987
		i. Create an RFbsGlyphDataIterator instance but do not open.
sl@0
   988
		ii. Call RFbsGlyphDataIterator::Close().
sl@0
   989
		
sl@0
   990
	Use case 2:
sl@0
   991
		i. Create an RFbsGlyphDataIterator instance and call RFbsGlyphDataIterator::Open().
sl@0
   992
		ii. Call RFbsGlyphDataIterator::Next() to prove the iterator is open.
sl@0
   993
		iii. Call RFbsGlyphDataIterator::Close().
sl@0
   994
		iv. Check that RFbsGlyphDataIterator::IsOpen() returns false.
sl@0
   995
	
sl@0
   996
@SYMTestExpectedResults
sl@0
   997
	Each call to RFbsGlyphDataIterator::IsOpen() returns the expected value.
sl@0
   998
*/
sl@0
   999
void CTFbsGlyphData::TestGlyphDataIteratorClose()
sl@0
  1000
	{
sl@0
  1001
	INFO_PRINTF1(_L("Test closing an RFbsGlyphDataIterator"));
sl@0
  1002
	__UHEAP_MARK;
sl@0
  1003
sl@0
  1004
	// Use case 1
sl@0
  1005
	RFbsGlyphDataIterator iter1;
sl@0
  1006
	iter1.Close();
sl@0
  1007
sl@0
  1008
	// Use case 2
sl@0
  1009
	RFbsGlyphDataIterator iter2;
sl@0
  1010
	TESTNOERROR(iter2.Open(*iFont, iGlyphCodesLatin, 1));
sl@0
  1011
	TInt iterErr = iter2.Next();
sl@0
  1012
	TESTE(KErrNotFound == iterErr, iterErr);
sl@0
  1013
	iter2.Close();
sl@0
  1014
	
sl@0
  1015
	__UHEAP_MARKEND;
sl@0
  1016
	}
sl@0
  1017
sl@0
  1018
/**
sl@0
  1019
@SYMTestCaseID		GRAPHICS-FBSERV-0629
sl@0
  1020
@SYMTestPriority	High
sl@0
  1021
@SYMTestType		UT
sl@0
  1022
@SYMTestStatus		Implemented
sl@0
  1023
@SYMPREQ			PREQ2678
sl@0
  1024
sl@0
  1025
@SYMTestCaseDesc
sl@0
  1026
	Show that the sequence of iterations when calling RFbsGlyphDataIterator::Next()
sl@0
  1027
	matches the order of the array of glyph codes.
sl@0
  1028
sl@0
  1029
@SYMTestActions
sl@0
  1030
	i. Create an RFbsGlyphDataIterator instance and call RFbsGlyphDataIterator::Open()
sl@0
  1031
		with an array of different glyph codes.
sl@0
  1032
	ii. Iterate through all the glyph data.
sl@0
  1033
		For each iteration check that the glyph code returned from 
sl@0
  1034
		RFbsGlyphDataIterator::GlyphCode() matches the corresponding glyph code
sl@0
  1035
		passed into Open().
sl@0
  1036
sl@0
  1037
@SYMTestExpectedResults
sl@0
  1038
	Each comparison of glyph code should match.
sl@0
  1039
*/
sl@0
  1040
void CTFbsGlyphData::TestGlyphDataIteratorSequence()
sl@0
  1041
	{
sl@0
  1042
	INFO_PRINTF1(_L("Test the iterator sequence of RFbsGlyphDataIterator"));
sl@0
  1043
	__UHEAP_MARK;
sl@0
  1044
	
sl@0
  1045
	TBool matches = ETrue;
sl@0
  1046
	TInt index = 0;
sl@0
  1047
sl@0
  1048
	RFbsGlyphDataIterator iter;
sl@0
  1049
	TInt iterErr = iter.Open(*iFont, iGlyphCodesLatin, KNumGlyphCodesLatin);
sl@0
  1050
	TESTNOERROR(iterErr);
sl@0
  1051
	for (; index < KNumGlyphCodesLatin && matches && (iterErr == KErrNone); iterErr = iter.Next(), index++)
sl@0
  1052
		{
sl@0
  1053
		if (iter.GlyphCode() != iGlyphCodesLatin[index])
sl@0
  1054
			{
sl@0
  1055
			ERR_PRINTF4(_L("Failed at iteration %d: wanted %d, got %d"), index, iGlyphCodesLatin[index], iter.GlyphCode());
sl@0
  1056
			matches = EFalse;
sl@0
  1057
			}
sl@0
  1058
		}
sl@0
  1059
	iter.Close();
sl@0
  1060
	TESTE(iterErr == KErrNotFound, iterErr);
sl@0
  1061
	TEST(matches);
sl@0
  1062
	TEST(index == KNumGlyphCodesLatin);
sl@0
  1063
	iter.Close();
sl@0
  1064
sl@0
  1065
	__UHEAP_MARKEND;
sl@0
  1066
	}
sl@0
  1067
sl@0
  1068
/**
sl@0
  1069
@SYMTestCaseID		GRAPHICS-FBSERV-0632
sl@0
  1070
@SYMTestPriority	High
sl@0
  1071
@SYMTestType		UT
sl@0
  1072
@SYMTestStatus		Implemented
sl@0
  1073
@SYMPREQ			PREQ2678
sl@0
  1074
sl@0
  1075
@SYMTestCaseDesc
sl@0
  1076
	Ensure it is possible to reuse a closed iterator on another CFbsFont.
sl@0
  1077
	
sl@0
  1078
@SYMTestActions
sl@0
  1079
	i. Open an RFbsGlyphDataIterator with sample data.
sl@0
  1080
	ii. Iterate through until the end of the iterator has been reached by calling 
sl@0
  1081
		Next() on the final element.
sl@0
  1082
	iii. Re-open the same RFbsGlyphDataIterator with sample data on a different CFbsFont.
sl@0
  1083
	iv. Iterate through a second time until the end has been reached by calling Next()
sl@0
  1084
		on the final element.
sl@0
  1085
	v. Close the iterator.
sl@0
  1086
	vi. During both iterations the bitmap data returned and metrics are compared with
sl@0
  1087
		the equivalent from GetCharacterData().
sl@0
  1088
sl@0
  1089
@SYMTestExpectedResults
sl@0
  1090
	The iterator should be opened successfully for both fonts and the data returned
sl@0
  1091
	should match the data from GetCharacterData().
sl@0
  1092
*/
sl@0
  1093
void CTFbsGlyphData::TestGlyphDataIteratorMultipleUsesOnMultipleFonts()
sl@0
  1094
	{
sl@0
  1095
	INFO_PRINTF1(_L("Reuse a closed iterator on a second CFbsFont"));
sl@0
  1096
	__UHEAP_MARK;
sl@0
  1097
	
sl@0
  1098
	const TUint8* bitmapData;
sl@0
  1099
	TSize bitmapSize;
sl@0
  1100
	TOpenFontCharMetrics charMetrics;
sl@0
  1101
	RFbsGlyphDataIterator iter;
sl@0
  1102
	
sl@0
  1103
	// Array of fonts to iterate through.
sl@0
  1104
	CFbsFont* font[2] = {iFont, iFont2};
sl@0
  1105
	
sl@0
  1106
	for (TInt fontId = 0; fontId < 2; fontId++)
sl@0
  1107
		{
sl@0
  1108
		// On the first iteration, open and use a font until all glyphs have been iterated through.
sl@0
  1109
		// On second iteration, use the same iterator on a different font and repeat.
sl@0
  1110
        CFbsFont* currentFont = font[fontId];
sl@0
  1111
sl@0
  1112
		//Open the iterator on the first font and compare the returned bitmaps against GetCharacterData
sl@0
  1113
		TInt iterErr = iter.Open(*currentFont, iGlyphCodesLatin, KNumGlyphCodesLatin);
sl@0
  1114
		TESTNOERROR(iterErr);
sl@0
  1115
		TFontSpec fontSpec = currentFont->FontSpecInTwips();
sl@0
  1116
		
sl@0
  1117
		TInt index = 0;
sl@0
  1118
		for (; (iterErr == KErrNone) && (index < KNumGlyphCodesLatin); iterErr = iter.Next(), ++index)
sl@0
  1119
			{
sl@0
  1120
			currentFont->GetCharacterData(iGlyphCodesLatin[index] | KGlyphCodeFlag, charMetrics, bitmapData, bitmapSize);
sl@0
  1121
			
sl@0
  1122
			TESTNOERROR(CompareMetrics(charMetrics, iter.Metrics()));
sl@0
  1123
			if (bitmapSize == TSize(0, 0))
sl@0
  1124
				{
sl@0
  1125
				TEST(bitmapSize == iter.Rect().Size());
sl@0
  1126
				}
sl@0
  1127
			else
sl@0
  1128
				{
sl@0
  1129
				// Compare images.
sl@0
  1130
				TBool match = EFalse;
sl@0
  1131
				RSgImage characterDataImage;
sl@0
  1132
				TInt err = CreateSgImageFromCharacterData(bitmapData, bitmapSize, fontSpec.iFontStyle.BitmapType(), characterDataImage);
sl@0
  1133
				if (err == KErrNone)
sl@0
  1134
					{
sl@0
  1135
					err = CompareSgImages(iEGL, iter.Image(), iter.Rect(), characterDataImage, TRect(bitmapSize), match);
sl@0
  1136
					}
sl@0
  1137
				characterDataImage.Close();
sl@0
  1138
				if (err != KErrNone)
sl@0
  1139
					{
sl@0
  1140
					TESTNOERROR(err);
sl@0
  1141
					break;
sl@0
  1142
					}
sl@0
  1143
				TEST(match);
sl@0
  1144
				}		
sl@0
  1145
			}
sl@0
  1146
		iter.Close();
sl@0
  1147
		TESTE(iterErr == KErrNotFound, iterErr);
sl@0
  1148
		TEST(index == KNumGlyphCodesLatin);
sl@0
  1149
		}
sl@0
  1150
	
sl@0
  1151
	__UHEAP_MARKEND;
sl@0
  1152
	}
sl@0
  1153
sl@0
  1154
/**
sl@0
  1155
@SYMTestCaseID		GRAPHICS-FBSERV-0633
sl@0
  1156
@SYMTestPriority	High
sl@0
  1157
@SYMTestType		UT
sl@0
  1158
@SYMTestStatus		Implemented
sl@0
  1159
@SYMPREQ			PREQ2678
sl@0
  1160
sl@0
  1161
@SYMTestCaseDesc
sl@0
  1162
	Check that for various Latin fonts, the images of the glyphs stored on the 
sl@0
  1163
	RSgImage matches those provided by GetCharacterData().
sl@0
  1164
sl@0
  1165
@SYMTestActions
sl@0
  1166
	Create a selection of fonts, using various typefaces, sizes and bitmap types.
sl@0
  1167
	For each font:
sl@0
  1168
	i. Open the RFbsGlyphDataIterator and iterate each glyph.
sl@0
  1169
	ii. For each glyph, call GetCharacterData() with the expected glyph code.
sl@0
  1170
	iii. Convert the character data to an RSgImage.
sl@0
  1171
	iv. Perform a comparison between the character RSgImage and the iterator 
sl@0
  1172
		image. 
sl@0
  1173
	v. After all iterations, close the iterator and check all expected glyphs
sl@0
  1174
		were iterated through.
sl@0
  1175
sl@0
  1176
@SYMTestExpectedResults
sl@0
  1177
	All glyph images should match.
sl@0
  1178
*/
sl@0
  1179
void CTFbsGlyphData::TestGlyphDataIteratorImageValidity()
sl@0
  1180
	{
sl@0
  1181
	INFO_PRINTF1(_L("Test the glyph images of the iterator match GetCharacterData()"));
sl@0
  1182
	__UHEAP_MARK;
sl@0
  1183
	
sl@0
  1184
	const TInt KNumFonts = 20;
sl@0
  1185
	
sl@0
  1186
	// Create a new typeface store for this test so that heap checking will not
sl@0
  1187
	// be affected by cached CFbsFonts.
sl@0
  1188
	CFbsTypefaceStore* typefaceStore = NULL;
sl@0
  1189
	TRAPD(err, typefaceStore = CFbsTypefaceStore::NewL(NULL));
sl@0
  1190
	if (err != KErrNone)
sl@0
  1191
		{
sl@0
  1192
		ERR_PRINTF1(_L("Failed to construct typeface store. Test aborted."));
sl@0
  1193
		__UHEAP_RESET;
sl@0
  1194
		iStep->SetTestStepResult(EFail);
sl@0
  1195
		return;
sl@0
  1196
		}
sl@0
  1197
	
sl@0
  1198
	for (TInt font = 0; font < KNumFonts; ++font)
sl@0
  1199
		{
sl@0
  1200
		// Use either a pre-created bitmap-font TFontSpec, or generate a Deja-vu one.
sl@0
  1201
		TFontSpec fontSpec = GenerateDejaVuFontSpec(font);
sl@0
  1202
		CFbsFont* latinFont = NULL;
sl@0
  1203
		TESTNOERROR(typefaceStore->GetNearestFontToDesignHeightInPixels((CFont*&)latinFont, fontSpec));	
sl@0
  1204
		
sl@0
  1205
		fontSpec = latinFont->FontSpecInTwips();
sl@0
  1206
		InfoPrintFontSpec(*latinFont);
sl@0
  1207
				
sl@0
  1208
		RFbsGlyphDataIterator iter;
sl@0
  1209
		TInt iterErr = iter.Open(*latinFont, iGlyphCodesLatin, KNumGlyphCodesLatin);
sl@0
  1210
		TESTNOERROR(iterErr);
sl@0
  1211
sl@0
  1212
		err = KErrNone;
sl@0
  1213
		TInt index = 0;
sl@0
  1214
		TInt numMismatches = 0;
sl@0
  1215
		// For each iteration, get the character data of the expected glyph.
sl@0
  1216
		// Create RSgImage from character data, and compare iter image with constructed image.
sl@0
  1217
		for (; (iterErr == KErrNone) && (err == KErrNone) && (index < KNumGlyphCodesLatin); (iterErr = iter.Next()), ++index)
sl@0
  1218
			{
sl@0
  1219
			TBool glyphMatches = ETrue;
sl@0
  1220
			const RSgImage& iteratorImage = iter.Image();
sl@0
  1221
sl@0
  1222
			const TUint8* bitmapData = NULL;
sl@0
  1223
			TSize bitmapSize;
sl@0
  1224
			TOpenFontCharMetrics metrics;
sl@0
  1225
			TInt characterDataAvailability = latinFont->GetCharacterData(iGlyphCodesLatin[index] | KGlyphCodeFlag, metrics, bitmapData, bitmapSize);
sl@0
  1226
			if (bitmapSize == TSize(0, 0))
sl@0
  1227
				{
sl@0
  1228
				glyphMatches = (bitmapSize == iter.Rect().Size());
sl@0
  1229
				}
sl@0
  1230
			else
sl@0
  1231
				{
sl@0
  1232
				RSgImage characterDataImage;
sl@0
  1233
				TESTNOERROR(CreateSgImageFromCharacterData(bitmapData, bitmapSize, fontSpec.iFontStyle.BitmapType(), characterDataImage));
sl@0
  1234
				err = CompareSgImages(iEGL, iteratorImage, iter.Rect(), characterDataImage, TRect(bitmapSize), glyphMatches);
sl@0
  1235
				characterDataImage.Close();
sl@0
  1236
				}
sl@0
  1237
			if (err == KErrNone && !glyphMatches)
sl@0
  1238
				{
sl@0
  1239
				ERR_PRINTF2(_L("Glyphcode %i : Image mismatch"), iGlyphCodesLatin[index]);
sl@0
  1240
				++numMismatches;
sl@0
  1241
				}
sl@0
  1242
			}
sl@0
  1243
		iter.Close();
sl@0
  1244
		TESTNOERROR(err);
sl@0
  1245
		TESTE(iterErr == KErrNotFound, iterErr);
sl@0
  1246
		TEST(index == KNumGlyphCodesLatin);	
sl@0
  1247
		TEST(numMismatches == 0);
sl@0
  1248
		typefaceStore->ReleaseFont(latinFont);
sl@0
  1249
		}
sl@0
  1250
	delete typefaceStore;
sl@0
  1251
	__UHEAP_MARKEND;
sl@0
  1252
	}
sl@0
  1253
sl@0
  1254
/**
sl@0
  1255
@SYMTestCaseID      GRAPHICS-FBSERV-0634
sl@0
  1256
@SYMTestPriority    High
sl@0
  1257
@SYMTestType        UT
sl@0
  1258
@SYMTestStatus      Implemented
sl@0
  1259
@SYMPREQ            PREQ2678
sl@0
  1260
sl@0
  1261
@SYMTestCaseDesc
sl@0
  1262
	To ensure that if the glyph image iterator has a current invalid 
sl@0
  1263
	character code, the SgImage returned by the iterator will match 
sl@0
  1264
	to the image obtained from the GetCharacterData() function
sl@0
  1265
@SYMTestActions
sl@0
  1266
	i. Retrieve bitmap data and metrics by using GetCharacterData().
sl@0
  1267
	ii. Open a glyph data iterator passing an invalid character code.
sl@0
  1268
	iii. If i. was unsuccessful, check that opening the iterator returned
sl@0
  1269
		an error code and skip to ix.
sl@0
  1270
	iv. Create SgImage from bitmap data.
sl@0
  1271
	v. Get SgImage from the glyph data iterator.
sl@0
  1272
	vi. Compare SgImages obtained on iv and v steps.
sl@0
  1273
	vii. Get font metrics from the glyph data iterator.
sl@0
  1274
	viii. Compare metrics obtained on i and vii steps.
sl@0
  1275
	vii. Close the iterator.
sl@0
  1276
sl@0
  1277
@SYMTestExpectedResults
sl@0
  1278
	If the request to get the character data failed, the return value of 
sl@0
  1279
	RFbsGlyphDataIterator::Open() must not be KErrNone.
sl@0
  1280
	Otherwise, images obtained from the iterator and GetCharacterData() should
sl@0
  1281
	match.
sl@0
  1282
*/
sl@0
  1283
void CTFbsGlyphData::TestGlyphDataIteratorOpenInvalidCode()
sl@0
  1284
	{
sl@0
  1285
	INFO_PRINTF1(_L("Ensure that the image returned by the iterator will \
sl@0
  1286
match to the image obtained from GetCharacterData() if character code is invalid"));
sl@0
  1287
	__UHEAP_MARK;
sl@0
  1288
sl@0
  1289
	const TUint8* bitmapData = NULL;
sl@0
  1290
	TSize bitmapSize;
sl@0
  1291
	TOpenFontCharMetrics metrics;
sl@0
  1292
	const TFontSpec fontSpec = iFont->FontSpecInTwips();
sl@0
  1293
	CFont::TCharacterDataAvailability availability = iFont->GetCharacterData(KDejaVuInvalidGlyphCode | KGlyphCodeFlag, metrics, bitmapData, bitmapSize);
sl@0
  1294
sl@0
  1295
	RFbsGlyphDataIterator iter;
sl@0
  1296
	TInt err = iter.Open(*iFont, &KDejaVuInvalidGlyphCode, 1);
sl@0
  1297
	if (availability == CFont::ENoCharacterData)
sl@0
  1298
		{
sl@0
  1299
		// Some rasterizers fail to return any data for KDejaVuInvalidGlyphCode, therefore
sl@0
  1300
		// rather than compare image contents, make sure RFbsGlyphDataIterator returns an error code.
sl@0
  1301
		WARN_PRINTF1(_L("Rasterizer failed to return data for invalid glyph code; not comparing image contents"));
sl@0
  1302
		TESTE(err != KErrNone, err);
sl@0
  1303
		}
sl@0
  1304
	else
sl@0
  1305
		{
sl@0
  1306
		TESTNOERROR(err);
sl@0
  1307
		if (err == KErrNone)
sl@0
  1308
			{
sl@0
  1309
			TBool glyphMatches = EFalse;
sl@0
  1310
			if (bitmapSize == TSize(0, 0))
sl@0
  1311
				{
sl@0
  1312
				glyphMatches = (bitmapSize == iter.Rect().Size());
sl@0
  1313
				}
sl@0
  1314
			else
sl@0
  1315
				{
sl@0
  1316
				RSgImage characterDataImage;
sl@0
  1317
				TESTNOERROR(CreateSgImageFromCharacterData(bitmapData, bitmapSize, fontSpec.iFontStyle.BitmapType(), characterDataImage));
sl@0
  1318
				TESTNOERROR(CompareSgImages(iEGL, iter.Image(), iter.Rect(), characterDataImage, TRect(bitmapSize), glyphMatches));
sl@0
  1319
				characterDataImage.Close();
sl@0
  1320
				}
sl@0
  1321
			TESTNOERROR(CompareMetrics(metrics, iter.Metrics()));
sl@0
  1322
			TEST(glyphMatches);
sl@0
  1323
			}
sl@0
  1324
		}
sl@0
  1325
	iter.Close();
sl@0
  1326
sl@0
  1327
	__UHEAP_MARKEND;
sl@0
  1328
	}
sl@0
  1329
sl@0
  1330
sl@0
  1331
/**
sl@0
  1332
@SYMTestCaseID      GRAPHICS-FBSERV-0636
sl@0
  1333
@SYMTestPriority    High
sl@0
  1334
@SYMTestType        UT
sl@0
  1335
@SYMTestStatus      Implemented
sl@0
  1336
@SYMPREQ            PREQ2678
sl@0
  1337
sl@0
  1338
@SYMTestCaseDesc
sl@0
  1339
	To ensure that opening the glyph data iterator which has already been opened with the same font
sl@0
  1340
	has no effect on the state of the iterator.
sl@0
  1341
@SYMTestActions
sl@0
  1342
	i. Open glyph data iterator on 2 glyph codes.
sl@0
  1343
	ii. Try to open the glyph data iterator again on the same font.
sl@0
  1344
	iii. Call RFbsGlyphDataIterator::Next() on the iterator and check error code, making the last
sl@0
  1345
		glyph code the current iteration.
sl@0
  1346
	iv. Call RFbsGlyphDataIterator::Next() again.
sl@0
  1347
@SYMTestExpectedResults
sl@0
  1348
	The second attempt to open the glyph data iterator will result an error with code KErrInUse.
sl@0
  1349
	The last two calls to RFbsGlyphDataIterator::Next() should return KErrNone and KErrNotFound
sl@0
  1350
	respectively, showing the iterator was not modified when the call to Open() failed.
sl@0
  1351
*/
sl@0
  1352
void CTFbsGlyphData::TestGlyphDataIteratorOpenTwice()
sl@0
  1353
	{
sl@0
  1354
	INFO_PRINTF1(_L("Ensure that opening the glyph data iterator which has already been opened with the same font has no effect"));
sl@0
  1355
	__UHEAP_MARK;
sl@0
  1356
sl@0
  1357
	RFbsGlyphDataIterator iter;
sl@0
  1358
	TInt iterErr = iter.Open(*iFont, iGlyphCodesLatin, 2);
sl@0
  1359
	TESTNOERROR(iterErr);
sl@0
  1360
	
sl@0
  1361
	iterErr = iter.Open(*iFont, iGlyphCodesLatin, KNumGlyphCodesLatin);
sl@0
  1362
	TESTE(iterErr == KErrInUse, iterErr);
sl@0
  1363
	iterErr = iter.Next();
sl@0
  1364
	TESTNOERROR(iterErr);
sl@0
  1365
	iterErr = iter.Next();
sl@0
  1366
	TESTE(iterErr == KErrNotFound, iterErr);
sl@0
  1367
	iter.Close();
sl@0
  1368
sl@0
  1369
	__UHEAP_MARKEND;
sl@0
  1370
	}
sl@0
  1371
sl@0
  1372
/**
sl@0
  1373
@SYMTestCaseID      GRAPHICS-FBSERV-0637
sl@0
  1374
@SYMTestPriority    High
sl@0
  1375
@SYMTestType        UT
sl@0
  1376
@SYMTestStatus      Implemented
sl@0
  1377
@SYMPREQ            PREQ2678
sl@0
  1378
sl@0
  1379
@SYMTestCaseDesc
sl@0
  1380
	To ensure that opening the glyph data iterator which has already been opened with different font
sl@0
  1381
	has no effect on the state of the iterator.
sl@0
  1382
@SYMTestActions
sl@0
  1383
	i. Open glyph data iterator on an 2 glyph codes
sl@0
  1384
	ii. Try to open the glyph data iterator again with a different font.
sl@0
  1385
	iii. Call RFbsGlyphDataIterator::Next() on the iterator and check error code, making the last
sl@0
  1386
		glyph code the current iteration.
sl@0
  1387
	iv. Call RFbsGlyphDataIterator::Next() again.
sl@0
  1388
@SYMTestExpectedResults
sl@0
  1389
	The second attempt to open the glyph data iterator will result an error with code KErrInUse.
sl@0
  1390
	The Next() call after this should return KErrNone, signifying the iterator is still open.
sl@0
  1391
	The last Next() call should return KErrNotFound, signifying the iterator has iterated 
sl@0
  1392
	through the two original glyph codes.
sl@0
  1393
*/
sl@0
  1394
void CTFbsGlyphData::TestGlyphDataIteratorOpenTwiceWithDifferentFonts()
sl@0
  1395
	{
sl@0
  1396
	INFO_PRINTF1(_L("Ensure that opening the glyph data iterator which has already been opened with different font has no effect"));
sl@0
  1397
	__UHEAP_MARK;
sl@0
  1398
sl@0
  1399
	RFbsGlyphDataIterator iter;
sl@0
  1400
	TInt iterErr = iter.Open(*iFont, iGlyphCodesLatin, 2);
sl@0
  1401
	TESTNOERROR(iterErr);
sl@0
  1402
sl@0
  1403
	iterErr = iter.Open(*iFont2, iGlyphCodesLatin, 2);
sl@0
  1404
	TESTE(iterErr == KErrInUse, iterErr);
sl@0
  1405
	iterErr = iter.Next();
sl@0
  1406
	TESTNOERROR(iterErr);
sl@0
  1407
	iterErr = iter.Next();
sl@0
  1408
	TESTE(iterErr == KErrNotFound, iterErr);
sl@0
  1409
	iter.Close();
sl@0
  1410
sl@0
  1411
	__UHEAP_MARKEND;
sl@0
  1412
	}
sl@0
  1413
sl@0
  1414
/**
sl@0
  1415
@SYMTestCaseID      GRAPHICS-FBSERV-0638
sl@0
  1416
@SYMTestPriority    High
sl@0
  1417
@SYMTestType        UT
sl@0
  1418
@SYMTestStatus      Implemented
sl@0
  1419
@SYMPREQ            PREQ2678
sl@0
  1420
sl@0
  1421
@SYMTestCaseDesc
sl@0
  1422
	To ensure that opening of glyph data iterator with the font greater than 
sl@0
  1423
	2048 by 2048 will not be supported 
sl@0
  1424
@SYMTestActions
sl@0
  1425
	i. Create font with the height greater than 2048
sl@0
  1426
	ii. Try to open the glyph data iterator with the font created on previous step
sl@0
  1427
	iii Release the font
sl@0
  1428
@SYMTestExpectedResults
sl@0
  1429
	Must fail with error code KErrTooBig
sl@0
  1430
*/
sl@0
  1431
void CTFbsGlyphData::TestGlyphDataIteratorOpenTooBigFont()
sl@0
  1432
	{
sl@0
  1433
	INFO_PRINTF1(_L("To ensure that opening of glyph data iterator with the font greater than 2048X2048 will not be supported"));
sl@0
  1434
	__UHEAP_MARK;
sl@0
  1435
sl@0
  1436
	CFbsFont* bigFont;
sl@0
  1437
	const TInt maxHeight = 2048;
sl@0
  1438
	const TInt maxHeightLimit = maxHeight + 20; //max size after we stop trying to create the font
sl@0
  1439
	// the loop below will guarantee that if the font with the size greater than 2048 is available it will be created
sl@0
  1440
	for(TInt height = maxHeight + 1; height < maxHeightLimit; height++)
sl@0
  1441
		{
sl@0
  1442
		TESTNOERROR(iTs->GetNearestFontToDesignHeightInPixels((CFont*&)bigFont, TFontSpec(KTypefaceName, height)));
sl@0
  1443
		TInt realHeight = bigFont->FontMaxHeight();
sl@0
  1444
		if(realHeight > maxHeight)
sl@0
  1445
			{
sl@0
  1446
			break;
sl@0
  1447
			}
sl@0
  1448
		iTs->ReleaseFont(bigFont);
sl@0
  1449
		bigFont = NULL;
sl@0
  1450
		}
sl@0
  1451
sl@0
  1452
	if (bigFont)
sl@0
  1453
		{
sl@0
  1454
		RFbsGlyphDataIterator iter;
sl@0
  1455
		TInt iterErr = iter.Open(*bigFont, iGlyphCodesLatin, KNumGlyphCodesLatin);
sl@0
  1456
		TESTE(iterErr == KErrTooBig, iterErr);
sl@0
  1457
		iTs->ReleaseFont(bigFont); 
sl@0
  1458
		}
sl@0
  1459
	else
sl@0
  1460
		{
sl@0
  1461
		//It is legitimate to fail to create the font, as there are no requirements for the rasterizer here to support such big font. 
sl@0
  1462
		//In this case we will skip the test.
sl@0
  1463
		WARN_PRINTF1(_L("Failed to create font with height greater than 2048"));
sl@0
  1464
		}
sl@0
  1465
sl@0
  1466
	__UHEAP_MARKEND;
sl@0
  1467
	}
sl@0
  1468
sl@0
  1469
sl@0
  1470
sl@0
  1471
sl@0
  1472
/**
sl@0
  1473
@SYMTestCaseID      GRAPHICS-FBSERV-0640
sl@0
  1474
@SYMTestPriority    High
sl@0
  1475
@SYMTestType        UT
sl@0
  1476
@SYMTestStatus      Implemented
sl@0
  1477
@SYMPREQ            PREQ2678
sl@0
  1478
sl@0
  1479
@SYMTestCaseDesc
sl@0
  1480
	To ensure that the glyph data iterator processes wrong arguments correctly
sl@0
  1481
@SYMTestActions
sl@0
  1482
	i. Try to open the glyph data iterator with the negative count passed in
sl@0
  1483
	ii. Try to open the glyph data iterator with the positive count and NULL 
sl@0
  1484
	glyph code array pointer passed in
sl@0
  1485
	iii. Try to open the glyph data iterator with a valid glyph code array and 
sl@0
  1486
	count equal to zero
sl@0
  1487
@SYMTestExpectedResults
sl@0
  1488
	At all steps the returned value is set to KErrArgument.
sl@0
  1489
*/
sl@0
  1490
void CTFbsGlyphData::TestGlyphDataIteratorOpenWithWrongArgument()
sl@0
  1491
	{
sl@0
  1492
	INFO_PRINTF1(_L("To ensure that the glyph data iterator processes wrong arguments correctly"));
sl@0
  1493
	__UHEAP_MARK;
sl@0
  1494
sl@0
  1495
	RFbsGlyphDataIterator iter;
sl@0
  1496
	TInt iterErr = iter.Open(*iFont, iGlyphCodesLatin, -1);
sl@0
  1497
	TESTE(iterErr == KErrArgument, iterErr);
sl@0
  1498
	
sl@0
  1499
	iterErr = iter.Open(*iFont, NULL, 1);
sl@0
  1500
	TESTE(iterErr == KErrArgument, iterErr);
sl@0
  1501
	
sl@0
  1502
	iterErr = iter.Open(*iFont, iGlyphCodesLatin, 0);
sl@0
  1503
	TESTE(iterErr == KErrArgument, iterErr);
sl@0
  1504
	
sl@0
  1505
	__UHEAP_MARKEND;
sl@0
  1506
	}
sl@0
  1507
sl@0
  1508
/**
sl@0
  1509
@SYMTestCaseID      GRAPHICS-FBSERV-0641
sl@0
  1510
@SYMTestPriority    High
sl@0
  1511
@SYMTestType        UT
sl@0
  1512
@SYMTestStatus      Implemented
sl@0
  1513
@SYMPREQ            PREQ2678
sl@0
  1514
sl@0
  1515
@SYMTestCaseDesc
sl@0
  1516
	To ensure that all allocated RSgImages were released after the
sl@0
  1517
	glyph data iterator has been opened and closed multiple times.
sl@0
  1518
sl@0
  1519
@SYMTestActions
sl@0
  1520
	i. Retrieve MSgDriver_Test interface from the SgDriver
sl@0
  1521
	ii. Mark alloc start and obtain resorce count from the interface
sl@0
  1522
	iii. Iterate through glyph data by calling RFbsGlyphDataIterator::Next() 
sl@0
  1523
	iv. Retrieve SgImage from the glyph data iterator instance
sl@0
  1524
	v. Repeate steps iii and iv multiple times
sl@0
  1525
	vi. Release font
sl@0
  1526
	vii.  Mark alloc end and obtain resorce count from the interface
sl@0
  1527
sl@0
  1528
@SYMTestExpectedResults
sl@0
  1529
	Resorce count at the end matches resorce count at the beginning. 
sl@0
  1530
*/
sl@0
  1531
void CTFbsGlyphData::TestGlyphDataIteratorImageMemoryLeak()
sl@0
  1532
	{
sl@0
  1533
	__UHEAP_MARK;
sl@0
  1534
	
sl@0
  1535
	MSgDriver_Test* sgDriverTestInterface = NULL; 
sl@0
  1536
	TInt err = iSgDriver.GetInterface(sgDriverTestInterface);
sl@0
  1537
	if(err != KErrNone)
sl@0
  1538
		{
sl@0
  1539
		__UHEAP_MARKEND;
sl@0
  1540
		WARN_PRINTF2(_L("Failed to obtain MSgDriver_Test interface with error code: %d, the test will be skipped"), err);
sl@0
  1541
		return;
sl@0
  1542
		}
sl@0
  1543
sl@0
  1544
	TEST(sgDriverTestInterface != NULL);
sl@0
  1545
	sgDriverTestInterface->AllocMarkStart();
sl@0
  1546
sl@0
  1547
	MSgDriver_Profiling* sgDriverProfilInterface = NULL;
sl@0
  1548
	err = iSgDriver.GetInterface(sgDriverProfilInterface);
sl@0
  1549
	if(err != KErrNone)
sl@0
  1550
		{
sl@0
  1551
		sgDriverTestInterface->AllocMarkEnd(0);
sl@0
  1552
		__UHEAP_MARKEND;
sl@0
  1553
		WARN_PRINTF2(_L("Failed to obtain MSgDriver_Profiling interface with error code: %d, the test will be skipped"), err);
sl@0
  1554
		return;
sl@0
  1555
		}
sl@0
  1556
	const TInt resCount = sgDriverProfilInterface->LocalResourceCount();
sl@0
  1557
sl@0
  1558
	CFbsFont* font = NULL;
sl@0
  1559
	err = iTs->GetNearestFontToDesignHeightInPixels((CFont*&)font, TFontSpec(KTypefaceName, 15));
sl@0
  1560
	TESTNOERROR(err);
sl@0
  1561
	if(err != KErrNone)
sl@0
  1562
		{
sl@0
  1563
		__UHEAP_MARKEND;
sl@0
  1564
		return;
sl@0
  1565
		}
sl@0
  1566
sl@0
  1567
	for (TInt ii = 0; ii < 10; ii++)
sl@0
  1568
		{
sl@0
  1569
		TInt index = 0;
sl@0
  1570
		RFbsGlyphDataIterator iter;
sl@0
  1571
		TInt iterErr = iter.Open(*font, iGlyphCodesLatin, KNumGlyphCodesLatin);
sl@0
  1572
		TESTNOERROR(iterErr);
sl@0
  1573
		for (; (iterErr == KErrNone) && (index < KNumGlyphCodesLatin); iterErr = iter.Next(), ++index)
sl@0
  1574
			{
sl@0
  1575
			const RSgImage& image = iter.Image();
sl@0
  1576
			}
sl@0
  1577
		iter.Close();
sl@0
  1578
		TEST(index == KNumGlyphCodesLatin);
sl@0
  1579
		TESTE(iterErr == KErrNotFound, iterErr);
sl@0
  1580
		}
sl@0
  1581
	iTs->ReleaseFont(font);
sl@0
  1582
	const TInt resCountEnd = sgDriverProfilInterface->LocalResourceCount();
sl@0
  1583
	TEST(resCountEnd == resCount);
sl@0
  1584
	sgDriverTestInterface->AllocMarkEnd(0);
sl@0
  1585
sl@0
  1586
	__UHEAP_MARKEND;
sl@0
  1587
	}
sl@0
  1588
sl@0
  1589
/**
sl@0
  1590
@SYMTestCaseID      GRAPHICS-FBSERV-0659
sl@0
  1591
@SYMTestPriority    Med
sl@0
  1592
@SYMTestType        UT
sl@0
  1593
@SYMTestStatus      Implemented
sl@0
  1594
@SYMPREQ            PREQ2678
sl@0
  1595
sl@0
  1596
@SYMTestCaseDesc
sl@0
  1597
	Uses the RFbsGlyphDataIterator to render a large amount of unique glyphs, at a very large 
sl@0
  1598
	size, to ensure that if graphics memory runs out while the iterator is in use, eviction 
sl@0
  1599
	takes place and does not corrupt the glyph images in any way.
sl@0
  1600
sl@0
  1601
@SYMTestActions
sl@0
  1602
	i. Create a large CFbsFont from the typeface store (size 100+)
sl@0
  1603
	ii. Simulate a low graphics-memory situation by creating enough RSgImages to fill the memory,
sl@0
  1604
		releasing one image in order to allow some small amount for the test.
sl@0
  1605
	iii. Open a RFbsGlyphDataIterator on the font, using a large array of unique glyph codes.
sl@0
  1606
	iv. Iterate through the glyphs, comparing each returned SgImage against the system-memory
sl@0
  1607
		representation of the glyph as returned by CFont::GetCharacterData().
sl@0
  1608
	v. Check for errors and mismatches, and release all images created by ii.
sl@0
  1609
	
sl@0
  1610
@SYMTestExpectedResults
sl@0
  1611
	At each iteration, each glyph should match in size and contents. 
sl@0
  1612
*/
sl@0
  1613
void CTFbsGlyphData::TestGlyphDataIteratorLargeFontStress()
sl@0
  1614
	{
sl@0
  1615
	INFO_PRINTF1(_L("Stress test using a RFbsGlyphDataIterator with a large font"));
sl@0
  1616
#ifdef __WINS__
sl@0
  1617
	// Cannot run test on emulator reliably - this is because on emulator
sl@0
  1618
	// system-memory is used for RSgImages, so using up RSgImage memory may 
sl@0
  1619
	// cause heap-allocation failures unrelated to the area being tested. 
sl@0
  1620
	// This test is specifically testing the behaviour when running out of
sl@0
  1621
	// RSgImage-based memory (i.e. graphics memory), but on emulator this 
sl@0
  1622
	// will cause a failed allocation anywhere.
sl@0
  1623
	INFO_PRINTF1(_L("Skipping test on emulator..."));
sl@0
  1624
#else
sl@0
  1625
	WARN_PRINTF1(_L("---Stress test TO BE REVISITED due to Broadcom defect ESLM-85LDV7 - TB10.1 Closing of RSgImage with duplicate handle used in same thread does not release GPU RAM"));
sl@0
  1626
	TEST(EFalse);
sl@0
  1627
/*	__UHEAP_MARK;
sl@0
  1628
sl@0
  1629
	const TInt KFontSize = 128;
sl@0
  1630
sl@0
  1631
	CFbsFont* font;
sl@0
  1632
	TInt err = iTs->GetNearestFontToDesignHeightInPixels((CFont*&)font, TFontSpec(KMonoTypefaceName, KFontSize));
sl@0
  1633
	TESTNOERROR(err);
sl@0
  1634
	// Output the actual fontspec used in the test.
sl@0
  1635
	InfoPrintFontSpec(*font);
sl@0
  1636
	
sl@0
  1637
	// Create 2 buffers for use in comparing SgImages so that we don't run out 
sl@0
  1638
	// of system memory through allocating memory in the test
sl@0
  1639
	TInt maxFontWidth = font->MaxCharWidthInPixels();
sl@0
  1640
	TInt maxFontHeight = font->HeightInPixels();
sl@0
  1641
	iTempBuf1 = (TUint8*) User::AllocZ(maxFontWidth * maxFontHeight);
sl@0
  1642
	iTempBuf2 = (TUint8*) User::AllocZ(maxFontWidth * maxFontHeight);
sl@0
  1643
sl@0
  1644
	// In order for the image comparisons to have enough memory to perform, keep 
sl@0
  1645
	// one large RSgImage which is created before the rest of the graphics memory 
sl@0
  1646
	// is filled.  This image can then be closed before doing the image comparison 
sl@0
  1647
	// and recreated after the image comparison to ensure that the graphics 
sl@0
  1648
	// memory is full.  Without this image, the image comparison could fail with 
sl@0
  1649
	// out of memory and the test would fail. 
sl@0
  1650
	RSgImage tempImage;
sl@0
  1651
	TESTNOERROR(tempImage.Create(TSgImageInfo(TSize(1000, 1000), ESgPixelFormatA_8, ESgUsageBitOpenVgImage)));
sl@0
  1652
sl@0
  1653
	TFontSpec actualFontSpec;
sl@0
  1654
	actualFontSpec = font->FontSpecInTwips();
sl@0
  1655
	
sl@0
  1656
	// Create RSgImages from character data independently from using iterator.
sl@0
  1657
	// These will be used for comparing with RSgImages retrieved from iterator.
sl@0
  1658
	RArray <RSgImage> sgImageFromCharDataArray;
sl@0
  1659
	TInt index = 0;
sl@0
  1660
	for(; (index < KNumGlyphCodesLatin) && (err == KErrNone); ++index)
sl@0
  1661
		{
sl@0
  1662
		RSgImage characterDataSgImage;
sl@0
  1663
		TInt err = KErrNone;
sl@0
  1664
		const TUint8* bitmapData = NULL;
sl@0
  1665
		TSize bitmapSize;
sl@0
  1666
		TOpenFontCharMetrics metrics;
sl@0
  1667
		font->GetCharacterData(iGlyphCodesLatin[index] | KGlyphCodeFlag, metrics, bitmapData, bitmapSize);
sl@0
  1668
sl@0
  1669
		if (bitmapSize != TSize(0, 0))
sl@0
  1670
			{
sl@0
  1671
			err = CreateSgImageFromCharacterData(bitmapData, bitmapSize, actualFontSpec.iFontStyle.BitmapType(), characterDataSgImage, iTempBuf1, iTempBuf2);
sl@0
  1672
			}
sl@0
  1673
		if (KErrNone == err)
sl@0
  1674
			{
sl@0
  1675
			err = sgImageFromCharDataArray.Append(characterDataSgImage);
sl@0
  1676
			}
sl@0
  1677
		}
sl@0
  1678
	TESTNOERROR(err);
sl@0
  1679
	TEST(index == KNumGlyphCodesLatin);
sl@0
  1680
sl@0
  1681
	// Simulate low OOGM situation by creating many RSgImages until out of memory.
sl@0
  1682
	RArray <RSgImage> sgImageArray;
sl@0
  1683
	if (err == KErrNone)
sl@0
  1684
		{
sl@0
  1685
		TESTNOERROR(NearlyFillGraphicsMemoryWithImages(TSize(256, 256), sgImageArray));
sl@0
  1686
		}
sl@0
  1687
	
sl@0
  1688
	// Open Iterator on long string of data...
sl@0
  1689
	RFbsGlyphDataIterator iter;
sl@0
  1690
	TInt iterErr = KErrNone;
sl@0
  1691
	if (err == KErrNone)
sl@0
  1692
		{
sl@0
  1693
		iterErr = iter.Open(*font, iGlyphCodesLatin, KNumGlyphCodesLatin);
sl@0
  1694
		TESTNOERROR(iterErr);
sl@0
  1695
		}
sl@0
  1696
sl@0
  1697
	// For each glyph, compare it to the system-memory version from GetCharacterData().
sl@0
  1698
	TInt numMismatches = 0;
sl@0
  1699
	for(index = 0; (iterErr == KErrNone) && (index < sgImageFromCharDataArray.Count()) && (err == KErrNone); iterErr = iter.Next(), ++index)
sl@0
  1700
		{
sl@0
  1701
		const TUint8* bitmapData = NULL;
sl@0
  1702
		TSize bitmapSize;
sl@0
  1703
		TOpenFontCharMetrics metrics;
sl@0
  1704
		font->GetCharacterData(iter.GlyphCode() | KGlyphCodeFlag, metrics, bitmapData, bitmapSize);
sl@0
  1705
sl@0
  1706
		if (iter.Rect().Size() == TSize(0, 0))
sl@0
  1707
			{
sl@0
  1708
			numMismatches += (bitmapSize != TSize(0, 0)) ? 1 : 0;
sl@0
  1709
			}
sl@0
  1710
		else
sl@0
  1711
			{
sl@0
  1712
			// Free up memory so that the image compariso succeeds
sl@0
  1713
			// Release all the images used to simulate OOGM.
sl@0
  1714
			for (TInt i = sgImageArray.Count() - 1; i >= 0; --i)
sl@0
  1715
				{
sl@0
  1716
				sgImageArray[i].Close();
sl@0
  1717
				sgImageArray.Remove(i);
sl@0
  1718
				}
sl@0
  1719
			
sl@0
  1720
			TBool match = ETrue;
sl@0
  1721
			err = CompareSgImages(iEGL, sgImageFromCharDataArray[index], TRect(bitmapSize), iTempBuf1, iter.Image(), iter.Rect(), iTempBuf2, match);
sl@0
  1722
			if (err == KErrNone && !match)
sl@0
  1723
				{
sl@0
  1724
				++numMismatches;
sl@0
  1725
				}
sl@0
  1726
			TInt result = FillGraphicsMemoryWithImages(TSize(256, 256), sgImageArray);
sl@0
  1727
			TESTE(result == KErrNoMemory || result == KErrNoGraphicsMemory, result);
sl@0
  1728
			}
sl@0
  1729
		}
sl@0
  1730
	iter.Close();
sl@0
  1731
sl@0
  1732
	// Release all images created from character data.
sl@0
  1733
	for (TInt i = sgImageFromCharDataArray.Count()-1; i >= 0; --i)
sl@0
  1734
		{
sl@0
  1735
		sgImageFromCharDataArray[i].Close();
sl@0
  1736
		}
sl@0
  1737
	sgImageFromCharDataArray.Close();
sl@0
  1738
sl@0
  1739
	// Release all the images used to simulate OOGM.
sl@0
  1740
	for (TInt i = sgImageArray.Count() - 1; i >= 0; --i)
sl@0
  1741
		{
sl@0
  1742
		sgImageArray[i].Close();
sl@0
  1743
		}
sl@0
  1744
	sgImageArray.Close();
sl@0
  1745
	tempImage.Close();
sl@0
  1746
	iTs->ReleaseFont(font);
sl@0
  1747
	User::Free(iTempBuf1);
sl@0
  1748
	User::Free(iTempBuf2);
sl@0
  1749
	iTempBuf1 = NULL;
sl@0
  1750
	iTempBuf2 = NULL;
sl@0
  1751
sl@0
  1752
	// Log any errors only after memory is freed - this ensures there is enough
sl@0
  1753
	// memory for the logger.
sl@0
  1754
	TESTNOERROR(err);
sl@0
  1755
	TESTE(iterErr == KErrNotFound, iterErr);
sl@0
  1756
	TEST(index == KNumGlyphCodesLatin);
sl@0
  1757
	TEST(numMismatches == 0);
sl@0
  1758
sl@0
  1759
	__UHEAP_MARKEND;*/
sl@0
  1760
#endif
sl@0
  1761
	}
sl@0
  1762
sl@0
  1763
/**
sl@0
  1764
@SYMTestCaseID      GRAPHICS-FBSERV-0660
sl@0
  1765
@SYMTestPriority    Med
sl@0
  1766
@SYMTestType        UT
sl@0
  1767
@SYMTestStatus      Implemented
sl@0
  1768
@SYMPREQ            PREQ2678
sl@0
  1769
sl@0
  1770
@SYMTestCaseDesc
sl@0
  1771
	Opens an RFbsGlyphDataIterator on many different fonts of different sizes and typefaces
sl@0
  1772
	and uses many fonts, in order to test that the iterator can cope with being used on many
sl@0
  1773
	fonts with many glyphs.
sl@0
  1774
sl@0
  1775
@SYMTestActions
sl@0
  1776
	i. Perform test of 100 iterations, where:
sl@0
  1777
		1. A new Latin font is created every iteration in order to force the Typeface Store
sl@0
  1778
			to create a brand-new server-side font at each iteration. 
sl@0
  1779
		2. For this font, open an RFbsGlyphDataIterator and cycle through all Latin glyphs.
sl@0
  1780
		3. For each glyph, compare against the glyph image returned by CFont::GetCharacterData().
sl@0
  1781
		4. Keep a record of the number of mismatches, and carry on to next font.
sl@0
  1782
	ii. Perform i. again, but using the existing fonts.
sl@0
  1783
	iii. Check that there are no mismatches, all glyphs and fonts were successfully checked, 
sl@0
  1784
		and no error codes returned during the test.
sl@0
  1785
	iv. Clean up all resources.
sl@0
  1786
	
sl@0
  1787
@SYMTestExpectedResults
sl@0
  1788
	The glyphs provided by the iterator should match that returned by GetCharacterData()
sl@0
  1789
	for every font and every iteration. 
sl@0
  1790
*/
sl@0
  1791
void CTFbsGlyphData::TestGlyphDataIteratorManyFontsStressL()
sl@0
  1792
	{
sl@0
  1793
	INFO_PRINTF1(_L("Stress test using a RFbsGlyphDataIterator with hundreds of fonts"));
sl@0
  1794
	WARN_PRINTF1(_L("---Stress test TO BE REVISITED due to Broadcom defect ESLM-85LDV7 - TB10.1 Closing of RSgImage with duplicate handle used in same thread does not release GPU RAM"));
sl@0
  1795
	TEST(EFalse);
sl@0
  1796
	/*__UHEAP_MARK;
sl@0
  1797
sl@0
  1798
	const TInt KNumFonts = 100;
sl@0
  1799
	const TInt KNumRepeatsPerFont = 2;
sl@0
  1800
	TInt err = KErrNone;
sl@0
  1801
	TInt numGlyphMismatches = 0;
sl@0
  1802
sl@0
  1803
	CFbsFont** font = new (ELeave) CFbsFont*[KNumFonts];
sl@0
  1804
	Mem::FillZ(font, sizeof(CFbsFont*) * KNumFonts);
sl@0
  1805
sl@0
  1806
	// Do the whole thing KNumRepeatsPerFont times. The second+ repeats will 
sl@0
  1807
	// re-use the fonts created in the first repeat, to ensure that fonts that 
sl@0
  1808
	// may have been evicted are able to be re-used with the iterator.
sl@0
  1809
	for (TInt rep = 0; (rep < KNumRepeatsPerFont) && (err == KErrNone); ++rep)
sl@0
  1810
		{
sl@0
  1811
		// Iterate through all the font variants:
sl@0
  1812
		// Iterate all font styles, for all latin typefaces, at increasing sizes.
sl@0
  1813
		TInt i = 0;
sl@0
  1814
		for (; (i < KNumFonts) && (err == KErrNone); ++i)
sl@0
  1815
			{
sl@0
  1816
			// Only create this font if this font isn't already valid (i.e. when this is the 
sl@0
  1817
			// first rep) otherwise re-use it.
sl@0
  1818
			if (!font[i])
sl@0
  1819
				{
sl@0
  1820
				TFontSpec requestedFontSpec = GenerateDejaVuFontSpec(i);
sl@0
  1821
				err = iTs->GetNearestFontToDesignHeightInPixels((CFont*&)font[i], requestedFontSpec);
sl@0
  1822
				}
sl@0
  1823
			if (err == KErrNone)
sl@0
  1824
				{
sl@0
  1825
				RFbsGlyphDataIterator iter;
sl@0
  1826
				TInt iterErr = iter.Open(*(font[i]), iGlyphCodesLatin, KNumGlyphCodesLatin);
sl@0
  1827
				if (iterErr != KErrNone)
sl@0
  1828
					{
sl@0
  1829
					ERR_PRINTF2(_L("Failed to open RFbsGlyphDataIterator [err=%d]"), iterErr);
sl@0
  1830
					InfoPrintFontSpec(*(font[i]));
sl@0
  1831
					iStep->SetTestStepResult(EFail);
sl@0
  1832
					}
sl@0
  1833
				else
sl@0
  1834
					{
sl@0
  1835
					TInt index = 0;
sl@0
  1836
					for(; (iterErr == KErrNone) && (index < KNumGlyphCodesLatin) && (err == KErrNone) ; iterErr = iter.Next(), index++)
sl@0
  1837
						{
sl@0
  1838
						const TUint8* bitmapData = NULL;
sl@0
  1839
						TSize bitmapSize;
sl@0
  1840
						TOpenFontCharMetrics metrics;
sl@0
  1841
						font[i]->GetCharacterData(iter.GlyphCode() | KGlyphCodeFlag, metrics, bitmapData, bitmapSize);
sl@0
  1842
						if (iter.Rect().Size() == TSize(0, 0))
sl@0
  1843
							{
sl@0
  1844
							numGlyphMismatches += (bitmapSize != TSize(0, 0)) ? 1 : 0;
sl@0
  1845
							}
sl@0
  1846
						else
sl@0
  1847
							{
sl@0
  1848
							TBool match = EFalse;
sl@0
  1849
							const TFontSpec fontSpec = font[i]->FontSpecInTwips();							
sl@0
  1850
							// Compare to system-memory version of glyph
sl@0
  1851
							RSgImage characterDataImage;
sl@0
  1852
							err = CreateSgImageFromCharacterData(bitmapData, bitmapSize, fontSpec.iFontStyle.BitmapType(), characterDataImage);
sl@0
  1853
							if (err == KErrNone) 
sl@0
  1854
								{
sl@0
  1855
								err = CompareSgImages(iEGL, iter.Image(), iter.Rect(), characterDataImage, TRect(bitmapSize), match);
sl@0
  1856
								}
sl@0
  1857
							if (err == KErrNone && !match)
sl@0
  1858
								{
sl@0
  1859
								++numGlyphMismatches;
sl@0
  1860
								}
sl@0
  1861
							characterDataImage.Close();
sl@0
  1862
							}					
sl@0
  1863
						}
sl@0
  1864
					iter.Close();
sl@0
  1865
					TESTE(iterErr == KErrNotFound, iterErr);
sl@0
  1866
					TEST(index == KNumGlyphCodesLatin);					
sl@0
  1867
					}
sl@0
  1868
				}
sl@0
  1869
			}
sl@0
  1870
		// Check all the fonts were iterated through.
sl@0
  1871
		TEST(i == KNumFonts);
sl@0
  1872
		}
sl@0
  1873
	TESTNOERROR(err);
sl@0
  1874
	TEST(numGlyphMismatches == 0);
sl@0
  1875
sl@0
  1876
	// Cleanup
sl@0
  1877
	for (TInt ii = 0; ii < KNumFonts; ii++)
sl@0
  1878
		{
sl@0
  1879
		iTs->ReleaseFont(font[ii]);
sl@0
  1880
		}
sl@0
  1881
	delete [] font;
sl@0
  1882
	__UHEAP_MARKEND;*/
sl@0
  1883
	}
sl@0
  1884
sl@0
  1885
/**
sl@0
  1886
@SYMTestCaseID      GRAPHICS-FBSERV-0662
sl@0
  1887
@SYMTestPriority    Low
sl@0
  1888
@SYMTestType        UT
sl@0
  1889
@SYMTestStatus      Implemented
sl@0
  1890
@SYMPREQ            PREQ2678
sl@0
  1891
sl@0
  1892
@SYMTestCaseDesc
sl@0
  1893
	Uses a RFbsGlyphDataIterator when there is no graphics memory available in the system.
sl@0
  1894
	It shows that when under low graphics memory, Next() returns the correct error code
sl@0
  1895
	as per the API (either KErrNoMemory or KErrNoGraphicsMemory, depending on the implementation 
sl@0
  1896
	of Graphics Resource being used).
sl@0
  1897
sl@0
  1898
@SYMTestActions
sl@0
  1899
	i. Create a CFbsFont from the typeface store.
sl@0
  1900
	ii. Simulate a low graphics-memory situation by creating enough RSgImages to fill the memory,
sl@0
  1901
	iii. Open a RFbsGlyphDataIterator on the font.
sl@0
  1902
	iv. Attempt to use the iterator, calling Next(), checking the returned code.
sl@0
  1903
	v. Close the iterator and release all graphics memory from ii.
sl@0
  1904
sl@0
  1905
@SYMTestExpectedResults
sl@0
  1906
	Next() should return either KErrNoMemory or KErrNoGraphicsMemory depending on the implmentation
sl@0
  1907
	of Graphics Resource used. It should return the same error as is returned when filling
sl@0
  1908
	the graphics memory reaches the limit.
sl@0
  1909
*/
sl@0
  1910
void CTFbsGlyphData::TestGlyphDataIteratorNoGraphicsMemory()
sl@0
  1911
	{
sl@0
  1912
	INFO_PRINTF1(_L("Test that when there is no GPU memory available, Next() returns correct error"));
sl@0
  1913
	WARN_PRINTF1(_L("---Stress test TO BE REVISITED due to Broadcom defect ESLM-85LDV7 - TB10.1 Closing of RSgImage with duplicate handle used in same thread does not release GPU RAM"));
sl@0
  1914
	TEST(EFalse);
sl@0
  1915
	/*__UHEAP_MARK;
sl@0
  1916
	
sl@0
  1917
	const TInt KFontSize = 128;
sl@0
  1918
	CFbsFont* font = NULL;
sl@0
  1919
	RFbsGlyphDataIterator iter;
sl@0
  1920
	
sl@0
  1921
	TInt err = iTs->GetNearestFontToDesignHeightInPixels((CFont*&)font, TFontSpec(KMonoTypefaceName, KFontSize));
sl@0
  1922
	TESTNOERROR(err);
sl@0
  1923
	
sl@0
  1924
	// Simulate low OOGM situation by creating many RSgImages until out of memory.
sl@0
  1925
	if (err == KErrNone)
sl@0
  1926
		{
sl@0
  1927
		InfoPrintFontSpec(*font);
sl@0
  1928
		RArray <RSgImage> sgImageArray;
sl@0
  1929
		TInt iterErr = KErrNone;
sl@0
  1930
		TInt gfxMemErr = FillGraphicsMemoryWithImages(TSize(KFontSize, KFontSize), sgImageArray);
sl@0
  1931
		TESTE(gfxMemErr == KErrNoMemory || gfxMemErr == KErrNoGraphicsMemory, gfxMemErr);
sl@0
  1932
		if (gfxMemErr == KErrNoMemory || gfxMemErr == KErrNoGraphicsMemory)
sl@0
  1933
			{
sl@0
  1934
			// Next() could either fail with KErrNoMemory or KErrNoGraphicsMemory, but should
sl@0
  1935
			// be the same error code as the last attempted creation of an SgImage, done in 
sl@0
  1936
			// FillGraphicsMemoryWithImages() so compare against that code.
sl@0
  1937
			iterErr = iter.Open(*font, iGlyphCodesLatin, KNumGlyphCodesLatin);
sl@0
  1938
			for (; iterErr == KErrNone; iterErr = iter.Next())
sl@0
  1939
				{
sl@0
  1940
				// no operation
sl@0
  1941
				}
sl@0
  1942
			iter.Close();
sl@0
  1943
			}
sl@0
  1944
	
sl@0
  1945
		// Release all the images used to simulate OOGM.
sl@0
  1946
		for (TInt i = sgImageArray.Count() - 1; i >= 0; --i)
sl@0
  1947
			{
sl@0
  1948
			sgImageArray[i].Close();
sl@0
  1949
			}
sl@0
  1950
		sgImageArray.Close();
sl@0
  1951
		
sl@0
  1952
		// Log any errors only after memory is freed - this ensures there is enough
sl@0
  1953
		// memory for the logger.
sl@0
  1954
		TESTE(iterErr == gfxMemErr, iterErr);
sl@0
  1955
		}
sl@0
  1956
sl@0
  1957
	iTs->ReleaseFont(font);
sl@0
  1958
	
sl@0
  1959
	__UHEAP_MARKEND;*/
sl@0
  1960
	}
sl@0
  1961
sl@0
  1962
/**
sl@0
  1963
@SYMTestCaseID      GRAPHICS-FBSERV-0666
sl@0
  1964
@SYMTestPriority    Low
sl@0
  1965
@SYMTestType        UT
sl@0
  1966
@SYMTestStatus      Implemented
sl@0
  1967
@SYMPREQ            PREQ2678
sl@0
  1968
sl@0
  1969
@SYMTestCaseDesc
sl@0
  1970
	Uses a RFbsGlyphDataIterator after Next() returns an error, in order to show that 
sl@0
  1971
	an error does not invalidate the state of the iterator and it is still usable. 
sl@0
  1972
sl@0
  1973
@SYMTestActions
sl@0
  1974
	i. Open the RFbsGlyphDataIterator on 1 glyph code.
sl@0
  1975
	ii. Store the data of the iterator and call Next() to reach the end of the iterator
sl@0
  1976
	iii. Access the glyph data repeatedly and check that the iterator members
sl@0
  1977
		 still match those in ii.
sl@0
  1978
sl@0
  1979
@SYMTestExpectedResults
sl@0
  1980
	The calls to Next() should cause KErrNotFound since it is past the final glyph.
sl@0
  1981
	The iterator data should match at all times since the iterator is never moved.
sl@0
  1982
*/
sl@0
  1983
void CTFbsGlyphData::TestGlyphDataIteratorNextIsAtomic()
sl@0
  1984
	{
sl@0
  1985
	INFO_PRINTF1(_L("To ensure that Next() is atomic, if it returns an error it is still useable"));
sl@0
  1986
	__UHEAP_MARK;
sl@0
  1987
sl@0
  1988
	RFbsGlyphDataIterator iter;
sl@0
  1989
	TInt iterErr = iter.Open(*iFont, iGlyphCodesLatin, 1);
sl@0
  1990
	TESTNOERROR(iterErr);
sl@0
  1991
	
sl@0
  1992
	TSgDrawableId id = iter.Image().Id();
sl@0
  1993
	TOpenFontCharMetrics metrics = iter.Metrics();
sl@0
  1994
	TUint glyphCode = iter.GlyphCode();
sl@0
  1995
	TRect rect = iter.Rect();
sl@0
  1996
	
sl@0
  1997
	for (TInt i = 0; i < 2; i++)
sl@0
  1998
		{
sl@0
  1999
		iterErr = iter.Next();
sl@0
  2000
		TESTE(iterErr == KErrNotFound, iterErr);
sl@0
  2001
		
sl@0
  2002
		TEST(id == iter.Image().Id());
sl@0
  2003
		TEST(glyphCode == iter.GlyphCode());
sl@0
  2004
		TEST(rect == iter.Rect());
sl@0
  2005
		TEST(CompareMetrics(metrics, iter.Metrics()) == 0);
sl@0
  2006
		}
sl@0
  2007
	iter.Close();
sl@0
  2008
		
sl@0
  2009
	__UHEAP_MARKEND;
sl@0
  2010
	}
sl@0
  2011
sl@0
  2012
/**
sl@0
  2013
@SYMTestCaseID      GRAPHICS-FBSERV-0665
sl@0
  2014
@SYMTestPriority    High
sl@0
  2015
@SYMTestType        UT
sl@0
  2016
@SYMTestStatus      Implemented
sl@0
  2017
@SYMPREQ            PREQ2678
sl@0
  2018
sl@0
  2019
@SYMTestCaseDesc
sl@0
  2020
	Glyph Atlas white-box test.
sl@0
  2021
	To ensure that the same RSgImage is used for repeated requests for the 
sl@0
  2022
	same glyph in the same call to RFbsGlyphDataIterator:Open().
sl@0
  2023
@SYMTestActions
sl@0
  2024
	i Open the glyph data iterator with a list of glyph codes which are all the same
sl@0
  2025
	ii Retrieve the drawable id of each iteration 
sl@0
  2026
	iii Check that the same drawable id is retrieved in each iteration  
sl@0
  2027
@SYMTestExpectedResults
sl@0
  2028
	Each iteration returns the same drawable id. 
sl@0
  2029
*/
sl@0
  2030
void CTFbsGlyphData::TestGlyphDataIteratorSameGlyphCodes()
sl@0
  2031
	{
sl@0
  2032
	INFO_PRINTF1(_L("White box test - Ensure that the same RSgImage is used for repeated requests for the same glyph in the same call to Open()"));
sl@0
  2033
	__UHEAP_MARK;
sl@0
  2034
sl@0
  2035
	const TUint KSameRepeatedGlyphCode = iGlyphCodesLatin['A' - 0x20];
sl@0
  2036
	const TInt KNumGlyphs = 10;
sl@0
  2037
	TUint* sameRepeatedGlyphCodes = new TUint[KNumGlyphs];
sl@0
  2038
	for (TInt ii = 0; ii < KNumGlyphs; ++ii)
sl@0
  2039
		{
sl@0
  2040
		sameRepeatedGlyphCodes[ii] = KSameRepeatedGlyphCode;
sl@0
  2041
		}
sl@0
  2042
	RFbsGlyphDataIterator iter;
sl@0
  2043
	TInt err = iter.Open(*iFont, sameRepeatedGlyphCodes, KNumGlyphs);
sl@0
  2044
	
sl@0
  2045
	TESTNOERROR(err);
sl@0
  2046
	if (KErrNone == err)
sl@0
  2047
		{
sl@0
  2048
		// get the drawable id of the first glyph and check that the id is valid
sl@0
  2049
		TSgDrawableId referenceId = iter.Image().Id();
sl@0
  2050
		RSgImage image;
sl@0
  2051
		TESTNOERROR(image.Open(referenceId));
sl@0
  2052
		image.Close();
sl@0
  2053
		TESTNOERROR(iter.Next());
sl@0
  2054
sl@0
  2055
		for (;KErrNone == err; err = iter.Next())
sl@0
  2056
			{
sl@0
  2057
			TEST(referenceId == iter.Image().Id());
sl@0
  2058
			}
sl@0
  2059
		TESTE(KErrNotFound == err, err);
sl@0
  2060
		}
sl@0
  2061
sl@0
  2062
	iter.Close();
sl@0
  2063
	delete[] sameRepeatedGlyphCodes;
sl@0
  2064
sl@0
  2065
	__UHEAP_MARKEND;
sl@0
  2066
	}
sl@0
  2067
sl@0
  2068
/**
sl@0
  2069
@SYMTestCaseID      GRAPHICS-FBSERV-0668
sl@0
  2070
@SYMTestPriority    High
sl@0
  2071
@SYMTestType        UT
sl@0
  2072
@SYMTestStatus      Implemented
sl@0
  2073
@SYMPREQ            PREQ2678
sl@0
  2074
sl@0
  2075
@SYMTestCaseDesc
sl@0
  2076
	To ensure that the iterator can successfully be opened on an array
sl@0
  2077
	of glyph codes of various array sizes. 
sl@0
  2078
@SYMTestActions
sl@0
  2079
	Perform many iterations of opening an array and cycling through the glyphs,
sl@0
  2080
	increasing the size of the array after each iteration. Some simple sanity-checking
sl@0
  2081
	of the glyphs is performed.
sl@0
  2082
@SYMTestExpectedResults
sl@0
  2083
	KErrNone should be returned at all times. 
sl@0
  2084
*/
sl@0
  2085
void CTFbsGlyphData::TestGlyphDataIteratorManyArraySizes()
sl@0
  2086
	{
sl@0
  2087
	INFO_PRINTF1(_L("Ensure that the RFbsGlyphDataIterator successfully opens glyph code arrays of many sizes"));
sl@0
  2088
	__UHEAP_MARK;
sl@0
  2089
	
sl@0
  2090
	RFbsGlyphMetricsArray glyphMetricsArray;
sl@0
  2091
	
sl@0
  2092
	TESTNOERROR(glyphMetricsArray.Get(*iFont, iGlyphCodesLatin, KNumGlyphCodesLatin));
sl@0
  2093
	TInt iterErr = KErrNone;
sl@0
  2094
	
sl@0
  2095
	for (TInt arraySize = 1; (arraySize < KNumGlyphCodesLatin) && (iterErr == KErrNone); ++arraySize)
sl@0
  2096
		{
sl@0
  2097
		RFbsGlyphDataIterator iter;
sl@0
  2098
		TInt iterErr = iter.Open(*iFont, iGlyphCodesLatin, arraySize);
sl@0
  2099
		TESTNOERROR(iterErr);
sl@0
  2100
		
sl@0
  2101
		for (TInt index = 0; iterErr == KErrNone; iterErr = iter.Next(), ++index)
sl@0
  2102
			{
sl@0
  2103
			// sanity checking...
sl@0
  2104
			if (iter.GlyphCode() != iGlyphCodesLatin[index])
sl@0
  2105
				{
sl@0
  2106
				ERR_PRINTF4(_L("Test failed at array size %d - Wanted glyphcode %d, got %d"), arraySize, iGlyphCodesLatin[index], iter.GlyphCode());
sl@0
  2107
				iStep->SetTestStepResult(EFail);
sl@0
  2108
				}
sl@0
  2109
			if (CompareMetrics(iter.Metrics(), glyphMetricsArray[index]) != 0)
sl@0
  2110
				{
sl@0
  2111
				ERR_PRINTF3(_L("Test failed at array size %d, metrics check failed at glyphcode %d"), arraySize, iGlyphCodesLatin[index]);
sl@0
  2112
				iStep->SetTestStepResult(EFail);
sl@0
  2113
				}			
sl@0
  2114
			}
sl@0
  2115
		iter.Close();
sl@0
  2116
		}
sl@0
  2117
sl@0
  2118
	glyphMetricsArray.Close();
sl@0
  2119
	TESTNOERROR(iterErr);
sl@0
  2120
sl@0
  2121
	__UHEAP_MARKEND;
sl@0
  2122
	}
sl@0
  2123
sl@0
  2124
/**
sl@0
  2125
@SYMTestCaseID      GRAPHICS-FBSERV-0669
sl@0
  2126
@SYMTestPriority    Low
sl@0
  2127
@SYMTestType        UT
sl@0
  2128
@SYMTestStatus      Implemented
sl@0
  2129
@SYMPREQ            PREQ2678
sl@0
  2130
sl@0
  2131
@SYMTestCaseDesc
sl@0
  2132
	Negative test case to show that RFbsGlyphDataIterator and RFbsGlyphMetricsArray
sl@0
  2133
	do not support bitmap fonts.
sl@0
  2134
@SYMTestActions
sl@0
  2135
	i. Load a bitmap font.
sl@0
  2136
	ii. Attempt to open an RFbsGlyphDataIterator and RFbsGlyphMetricsArray with the font.
sl@0
  2137
@SYMTestExpectedResults
sl@0
  2138
	KErrNotSupported should be returned in both instances. 
sl@0
  2139
*/
sl@0
  2140
 void CTFbsGlyphData::TestBitmapFontSupport()
sl@0
  2141
	{
sl@0
  2142
	INFO_PRINTF1(_L("Test bitmap font not supported"));
sl@0
  2143
	__UHEAP_MARK;
sl@0
  2144
	
sl@0
  2145
	CFbsFont* bitmapFont = NULL;
sl@0
  2146
	TInt err = iTs->GetNearestFontToDesignHeightInPixels((CFont*&)bitmapFont, TFontSpec(_L("Digital"), 14));
sl@0
  2147
	TESTNOERROR(err);
sl@0
  2148
	TEST(!bitmapFont->IsOpenFont());
sl@0
  2149
	
sl@0
  2150
	RFbsGlyphDataIterator iter;
sl@0
  2151
	err = iter.Open(*bitmapFont, iGlyphCodesLatin, KNumGlyphCodesLatin);
sl@0
  2152
	TEST(err == KErrNotSupported);
sl@0
  2153
	iter.Close();
sl@0
  2154
	
sl@0
  2155
	RFbsGlyphMetricsArray array;
sl@0
  2156
	err = array.Get(*bitmapFont, iGlyphCodesLatin, KNumGlyphCodesLatin);
sl@0
  2157
	TEST(err == KErrNotSupported);
sl@0
  2158
	array.Close();
sl@0
  2159
	
sl@0
  2160
	iTs->ReleaseFont(bitmapFont);
sl@0
  2161
	__UHEAP_MARKEND;
sl@0
  2162
	}
sl@0
  2163
 
sl@0
  2164
/**
sl@0
  2165
@SYMTestCaseID		GRAPHICS-FBSERV-0671
sl@0
  2166
@SYMTestPriority	High
sl@0
  2167
@SYMTestType		UT
sl@0
  2168
@SYMTestStatus		Implemented
sl@0
  2169
@SYMPREQ			PREQ2678
sl@0
  2170
sl@0
  2171
@SYMTestCaseDesc
sl@0
  2172
	Shows that different threads (and therefore RFbsSessions) using fonts with the same
sl@0
  2173
	TFontSpec share the same glyphs	in the atlas and do not create duplicate entries
sl@0
  2174
	in the Glyph Atlas, and that releasing a font clears all associated glyphs in the
sl@0
  2175
	atlas.
sl@0
  2176
sl@0
  2177
@SYMTestActions
sl@0
  2178
	i. Create a handle to a test font in the current process.
sl@0
  2179
	ii. Spawn a test thread and wait for it to complete. Within the thread :
sl@0
  2180
		1. Create a font with the same fontspec as the parent process.
sl@0
  2181
		2. Use the RFbsGlyphDataIterator API to force rasterization into the glyph atlas.
sl@0
  2182
		3. Release the iterator.
sl@0
  2183
	iii. Check there were no leaves from the thread.
sl@0
  2184
	iv. Repeat ii. and iii. several times. Before using RFbsGlyphDataIterator,
sl@0
  2185
		the thread checks that the glyphs are still in the atlas from the first thread.
sl@0
  2186
	v. Check that the number of fonts in the atlas has increased by one only.
sl@0
  2187
	vi. Check that the number of glyphs in the atlas has increased by the size of the 
sl@0
  2188
		glyph code array.
sl@0
  2189
	vii. Release the font in the parent process, thereby releasing the font and glyphs
sl@0
  2190
		in the glyph atlas, and check that the state of the atlas is the same as before
sl@0
  2191
		the test is run.
sl@0
  2192
sl@0
  2193
@SYMTestExpectedResults
sl@0
  2194
	All threads should return no errors or leaves or panics.
sl@0
  2195
	After all threads have finished:
sl@0
  2196
		The glyph count should have increased by the size of the glyph code array used
sl@0
  2197
		in the RFbsGlyphDataIterator, showing that	glyphs are only being added to the atlas
sl@0
  2198
		once. The number of fonts in the atlas should have increased by one, showing
sl@0
  2199
		that only the single underlying font object is being added to the atlas, despite
sl@0
  2200
		different RFbsSessions and CFbsFont instances used.
sl@0
  2201
	After the test font is released in the main process:
sl@0
  2202
		The glyph count and font count return to the pre-test value, showing that when
sl@0
  2203
		the last handle to a TFontSpec is released, the atlas frees its associated data.
sl@0
  2204
*/
sl@0
  2205
void CTFbsGlyphData::TestMultithreadShareSingleFont()
sl@0
  2206
	{
sl@0
  2207
	INFO_PRINTF1(_L("Test glyphs shared between RFbsSessions/threads/processes"));
sl@0
  2208
#ifndef _DEBUG
sl@0
  2209
	// Test relies on debug-only FBS messages EFbsMessAtlasGlyphCount and EFbsMessAtlasFontCount
sl@0
  2210
	INFO_PRINTF1(_L("Skipping test in release mode"));
sl@0
  2211
#else	
sl@0
  2212
	__UHEAP_MARK;
sl@0
  2213
sl@0
  2214
	_LIT(KThreadName, "GlyphDataTestThread");
sl@0
  2215
	const TInt KNumTestThreads = 5;
sl@0
  2216
	const TFontSpec KTestFontSpec(KTypefaceName, 50);	
sl@0
  2217
	const TInt atlasFontCountStart = iFbs->SendCommand(EFbsMessAtlasFontCount);
sl@0
  2218
	const TInt atlasGlyphCountStart = iFbs->SendCommand(EFbsMessAtlasGlyphCount);
sl@0
  2219
sl@0
  2220
	CFbsFont* testFont;
sl@0
  2221
	TInt err = iTs->GetNearestFontToDesignHeightInPixels( (CFont*&)testFont, KTestFontSpec);
sl@0
  2222
	if (err != KErrNone)
sl@0
  2223
		{
sl@0
  2224
		ERR_PRINTF2(_L("Could not load font, err = %d"), err);
sl@0
  2225
		iStep->SetTestStepResult(EFail);
sl@0
  2226
		return;
sl@0
  2227
		}
sl@0
  2228
	
sl@0
  2229
	// Check there are no glyphs belonging to the test font before the test starts.
sl@0
  2230
	TInt atlasFontGlyphCount = iFbs->SendCommand(EFbsMessAtlasGlyphCount, testFont->Handle());
sl@0
  2231
	TEST(atlasFontGlyphCount == 0);
sl@0
  2232
sl@0
  2233
	TGlyphDataMultithreadParams params = {KTestFontSpec, iGlyphCodesLatin, KNumGlyphCodesLatin, NULL};
sl@0
  2234
sl@0
  2235
	// Run the test threads sequentially, and check its exit status.
sl@0
  2236
	RThread testThread;
sl@0
  2237
	TInt numThreadsPassed = 0;
sl@0
  2238
	for (TInt i = 0; i < KNumTestThreads; i++)
sl@0
  2239
		{
sl@0
  2240
		TBool threadPassed = ETrue;
sl@0
  2241
		TGlyphDataThreadInfo info = {EGlyphDataMultiSessionTestShareGlyphs, params, i, iStep};
sl@0
  2242
		err = testThread.Create(KThreadName, CTFbsGlyphData::ThreadFunction, KDefaultStackSize, KTestThreadMinHeapSize, KTestThreadMaxHeapSize, &info);
sl@0
  2243
		TESTNOERROR(err);
sl@0
  2244
sl@0
  2245
		TRequestStatus statusThread;
sl@0
  2246
		testThread.Logon(statusThread);
sl@0
  2247
		testThread.Resume();
sl@0
  2248
		
sl@0
  2249
		User::WaitForRequest(statusThread);
sl@0
  2250
		TInt threadResult = testThread.ExitReason();
sl@0
  2251
		if (threadResult != KErrNone)
sl@0
  2252
			{
sl@0
  2253
			ERR_PRINTF3(_L("Thread %i: Terminated with reason %d"), i, threadResult);
sl@0
  2254
			threadPassed = EFalse; 
sl@0
  2255
			}
sl@0
  2256
		TExitCategoryName exitCategory = testThread.ExitCategory();
sl@0
  2257
		if (exitCategory.Compare(_L("Kill")) != 0)
sl@0
  2258
			{
sl@0
  2259
			ERR_PRINTF3(_L("Thread %i: Terminated with reason category '%S'"), i, &exitCategory);
sl@0
  2260
			threadPassed = EFalse;
sl@0
  2261
			}
sl@0
  2262
		testThread.Close();
sl@0
  2263
		numThreadsPassed += (threadPassed) ? 1 : 0;
sl@0
  2264
		}
sl@0
  2265
	TEST(numThreadsPassed == KNumTestThreads);
sl@0
  2266
sl@0
  2267
	// Check that the atlas still contains the glyphs and the font created by the threads
sl@0
  2268
	// after they have died, since the font is still open in this process.
sl@0
  2269
	atlasFontGlyphCount = iFbs->SendCommand(EFbsMessAtlasGlyphCount, testFont->Handle());
sl@0
  2270
	TEST(atlasFontGlyphCount == params.iGlyphCodesCount);
sl@0
  2271
	TInt atlasFontCount = iFbs->SendCommand(EFbsMessAtlasFontCount);
sl@0
  2272
	TEST(atlasFontCount == (atlasFontCountStart + 1));
sl@0
  2273
sl@0
  2274
	iTs->ReleaseFont(testFont);
sl@0
  2275
	testFont = NULL;
sl@0
  2276
sl@0
  2277
	// Check the atlas state is now the same as it was before the test started,
sl@0
  2278
	// now that the last remaining handle to the font used in the threads is released.
sl@0
  2279
	TInt atlasGlyphCountEnd = iFbs->SendCommand(EFbsMessAtlasGlyphCount);
sl@0
  2280
	TEST(atlasGlyphCountStart == atlasGlyphCountEnd);
sl@0
  2281
	TInt atlasFontCountEnd = iFbs->SendCommand(EFbsMessAtlasFontCount);
sl@0
  2282
	TEST(atlasFontCountStart == atlasFontCountEnd);
sl@0
  2283
	__UHEAP_MARKEND;
sl@0
  2284
#endif
sl@0
  2285
	}
sl@0
  2286
sl@0
  2287
/**
sl@0
  2288
Worker thread for TestMultithreadShareSingleFont().
sl@0
  2289
The thread uses RFbsGlyphDataIterator on a CFbsFont of the given TFontSpec.
sl@0
  2290
Once complete the atlas is queried for the number of associated glyphs.
sl@0
  2291
 */
sl@0
  2292
void CTFbsGlyphData::ThreadShareGlyphsL(TInt aThreadNum, TGlyphDataMultithreadParams& aParam, CTestStep* aStep)
sl@0
  2293
	{
sl@0
  2294
	User::LeaveIfError(RFbsSession::Connect());
sl@0
  2295
	CFbsTypefaceStore* ts = CFbsTypefaceStore::NewL(NULL);
sl@0
  2296
	CleanupStack::PushL(ts);
sl@0
  2297
	RFbsSession* fbs = RFbsSession::GetSession();
sl@0
  2298
sl@0
  2299
	CFbsFont* font;
sl@0
  2300
	TInt err = ts->GetNearestFontToDesignHeightInPixels((CFont*&)font, aParam.iFontSpec);
sl@0
  2301
	User::LeaveIfError(err);
sl@0
  2302
sl@0
  2303
	if (aThreadNum > 0)
sl@0
  2304
		{
sl@0
  2305
		// If this is not the first thread, it means the first thread has already executed and 
sl@0
  2306
		// populated the glyph atlas with the glyphs. The font created by this thread 
sl@0
  2307
		// should already have its glyphs in the atlas.
sl@0
  2308
		TInt fontGlyphCount = fbs->SendCommand(EFbsMessAtlasGlyphCount, font->Handle());
sl@0
  2309
		if (fontGlyphCount != aParam.iGlyphCodesCount)
sl@0
  2310
			{
sl@0
  2311
			aStep->ERR_PRINTF4(_L("Thread %d: Only %d glyphs in atlas before first iteration, expected %d"), aThreadNum, fontGlyphCount, aParam.iGlyphCodesCount);
sl@0
  2312
			aStep->SetTestStepResult(EFail);
sl@0
  2313
			}
sl@0
  2314
		}
sl@0
  2315
sl@0
  2316
	RFbsGlyphDataIterator iter;
sl@0
  2317
	for (err = iter.Open(*font, aParam.iGlyphCodes, aParam.iGlyphCodesCount); err == KErrNone; err = iter.Next())
sl@0
  2318
		{
sl@0
  2319
		// no-op
sl@0
  2320
		}
sl@0
  2321
	iter.Close();
sl@0
  2322
sl@0
  2323
	// Check that the glyphs of this font have been added to the atlas
sl@0
  2324
	TInt fontGlyphCount = fbs->SendCommand(EFbsMessAtlasGlyphCount, font->Handle());
sl@0
  2325
	if (fontGlyphCount != aParam.iGlyphCodesCount)
sl@0
  2326
		{
sl@0
  2327
		aStep->ERR_PRINTF5(_L("Thread %d: Only %d glyphs in atlas after last iteration, expected %d (err=%d)"), aThreadNum, fontGlyphCount, aParam.iGlyphCodesCount, err);
sl@0
  2328
		aStep->SetTestStepResult(EFail);
sl@0
  2329
		}
sl@0
  2330
	if (err != KErrNotFound)
sl@0
  2331
		{
sl@0
  2332
		aStep->ERR_PRINTF3(_L("Thread %d: Error during test = %d"), aThreadNum, err);
sl@0
  2333
		aStep->SetTestStepResult(EFail);
sl@0
  2334
		}
sl@0
  2335
sl@0
  2336
	ts->ReleaseFont(font);
sl@0
  2337
	CleanupStack::PopAndDestroy(1); // ts
sl@0
  2338
	RFbsSession::Disconnect();
sl@0
  2339
	}
sl@0
  2340
sl@0
  2341
sl@0
  2342
/**
sl@0
  2343
@SYMTestCaseID		GRAPHICS-FBSERV-0672
sl@0
  2344
@SYMTestPriority	Medium
sl@0
  2345
@SYMTestType		UT
sl@0
  2346
@SYMTestStatus		Implemented
sl@0
  2347
@SYMPREQ			PREQ2678
sl@0
  2348
sl@0
  2349
@SYMTestCaseDesc
sl@0
  2350
	Tests that with many concurrent sessions connected to Fbserv, the atlas successfully
sl@0
  2351
	returns the correct glyph images even if the atlas becomes full and has to evict glyphs.
sl@0
  2352
sl@0
  2353
@SYMTestActions
sl@0
  2354
	i. Create 25 threads, each a unique session with Fbserv.
sl@0
  2355
	ii. Launch the threads simultaneously. In each thread:
sl@0
  2356
		1. Create a FBS typeface store and create a font which is unique in the process.
sl@0
  2357
		2. Use RFbsGlyphDataIterator to iterate through the latin glyph codes.
sl@0
  2358
		3. Check the image is correct for each glyph against the image returned by 
sl@0
  2359
			CFont::GetCharacterData().
sl@0
  2360
		4. Close the iterator.
sl@0
  2361
		5. Release the font and close the typeface store. 
sl@0
  2362
	iii. Once all threads have finished, check the exit status of each thread
sl@0
  2363
sl@0
  2364
@SYMTestExpectedResults
sl@0
  2365
	Every glyph for every thread should match the image returned by GetCharacterData()
sl@0
  2366
	All threads should exit normally with no Leave code.
sl@0
  2367
*/
sl@0
  2368
_LIT(KTestMultithreadStressFinishSemaphore, "TestMultithreadStressAtlasFinish");
sl@0
  2369
sl@0
  2370
void CTFbsGlyphData::TestMultithreadStressAtlas()
sl@0
  2371
	{
sl@0
  2372
	INFO_PRINTF1(_L("Stress test glyph atlas with multiple RFbsSessions"));
sl@0
  2373
	WARN_PRINTF1(_L("---Stress test TO BE REVISITED due to Broadcom defect ESLM-85NEFT - TB10.1 eglCreateImageKHR hangs during multithreading"));
sl@0
  2374
	TEST(EFalse);
sl@0
  2375
	/*__UHEAP_MARK;
sl@0
  2376
sl@0
  2377
	TInt err = KErrNone;
sl@0
  2378
	const TInt KNumTestThreads = 25;
sl@0
  2379
	_LIT(KThreadNameFormat, "GlyphDataTestThread%i");
sl@0
  2380
sl@0
  2381
	// Create a semaphore that is signalled by each test thread when it has finished.
sl@0
  2382
	RSemaphore threadFinishSemaphore;
sl@0
  2383
	err = threadFinishSemaphore.CreateGlobal(KTestMultithreadStressFinishSemaphore, 0, EOwnerThread);
sl@0
  2384
	TESTNOERROR(err);
sl@0
  2385
sl@0
  2386
	// Prepare the testdata for the threads
sl@0
  2387
	// Each thread will have a TFontSpec which will cause unique CFbsFonts
sl@0
  2388
	// to be created in the server, and therefore the atlas.
sl@0
  2389
	RThread testThread[KNumTestThreads];
sl@0
  2390
	TGlyphDataThreadInfo testInfo[KNumTestThreads];	
sl@0
  2391
	for (TInt i = 0; i < KNumTestThreads; ++i)
sl@0
  2392
		{
sl@0
  2393
		testInfo[i].iStep = iStep;
sl@0
  2394
		testInfo[i].iTest = EGlyphDataMultiSessionTestStressAtlas;
sl@0
  2395
		testInfo[i].iParams.iFontSpec = GenerateDejaVuFontSpec(i);
sl@0
  2396
		testInfo[i].iParams.iGlyphCodes = iGlyphCodesLatin;
sl@0
  2397
		testInfo[i].iParams.iGlyphCodesCount = KNumGlyphCodesLatin;
sl@0
  2398
		testInfo[i].iParams.iEGL = iEGL;
sl@0
  2399
		testInfo[i].iThreadNum = i;	
sl@0
  2400
		TBuf<128> threadName;
sl@0
  2401
		threadName.AppendFormat(KThreadNameFormat, i);
sl@0
  2402
		err = testThread[i].Create(threadName, CTFbsGlyphData::ThreadFunction, KDefaultStackSize, KTestThreadMinHeapSize, KTestThreadMaxHeapSize, &testInfo[i]);
sl@0
  2403
		TESTNOERROR(err);
sl@0
  2404
		}
sl@0
  2405
sl@0
  2406
	// All threads are created, start them simultaneously.
sl@0
  2407
	for (TInt i = 0; i < KNumTestThreads; ++i)
sl@0
  2408
		{
sl@0
  2409
		testThread[i].Resume();
sl@0
  2410
		}
sl@0
  2411
	// Wait for all threads to finish.
sl@0
  2412
	for (TInt i = 0; i < KNumTestThreads; ++i)
sl@0
  2413
		{
sl@0
  2414
		threadFinishSemaphore.Wait();
sl@0
  2415
		}
sl@0
  2416
	// Allow some time for remaining threads to finish tidy-up.
sl@0
  2417
	User::After(100000);
sl@0
  2418
	threadFinishSemaphore.Close();
sl@0
  2419
sl@0
  2420
	TInt numThreadsPassed = 0;
sl@0
  2421
	for (TInt i = 0; i < KNumTestThreads; ++i)
sl@0
  2422
		{
sl@0
  2423
		TBool threadPassed = ETrue;
sl@0
  2424
		TInt threadResult = testThread[i].ExitReason();
sl@0
  2425
		if (threadResult != KErrNone)
sl@0
  2426
			{
sl@0
  2427
			ERR_PRINTF3(_L("Thread %i: Terminated with reason %d"), i, threadResult);
sl@0
  2428
			threadPassed = EFalse; 
sl@0
  2429
			}
sl@0
  2430
		TExitCategoryName exitCategory = testThread[i].ExitCategory();
sl@0
  2431
		if (exitCategory.Compare(_L("Kill")) != 0)
sl@0
  2432
			{
sl@0
  2433
			ERR_PRINTF3(_L("Thread %i: Terminated with reason category '%S'"), i, &exitCategory);
sl@0
  2434
			threadPassed = EFalse;
sl@0
  2435
			}
sl@0
  2436
		testThread[i].Close();
sl@0
  2437
		numThreadsPassed += (threadPassed) ? 1 : 0;
sl@0
  2438
		}
sl@0
  2439
	TEST(numThreadsPassed == KNumTestThreads);
sl@0
  2440
sl@0
  2441
	__UHEAP_MARKEND;*/
sl@0
  2442
	}
sl@0
  2443
/**
sl@0
  2444
Worker thread for TestMultithreadStressAtlas().
sl@0
  2445
The thread uses RFbsGlyphDataIterator on a CFbsFont of the given TFontSpec.
sl@0
  2446
For each glyph, the image returned by the iterator is compared to the image 
sl@0
  2447
returned from CFont::GetCharacterData().
sl@0
  2448
Once complete, the semaphore is signalled to tell the parent process it has
sl@0
  2449
finished.
sl@0
  2450
 */
sl@0
  2451
void CleanupFinishSemaphore(TAny* aItem)
sl@0
  2452
    {
sl@0
  2453
    RSemaphore* semaphore = reinterpret_cast<RSemaphore*>(aItem);
sl@0
  2454
    semaphore->Signal();
sl@0
  2455
    semaphore->Close();
sl@0
  2456
    }
sl@0
  2457
void CTFbsGlyphData::ThreadStressAtlasL(TInt aThreadNum, TGlyphDataMultithreadParams& aParam, CTestStep* aStep)
sl@0
  2458
	{
sl@0
  2459
	TOpenFontCharMetrics charMetrics;
sl@0
  2460
	const TUint8* bitmapData;
sl@0
  2461
	TSize bitmapSize;
sl@0
  2462
	RSgImage charDataImage;
sl@0
  2463
sl@0
  2464
	RSemaphore threadFinishSemaphore;
sl@0
  2465
	User::LeaveIfError(threadFinishSemaphore.OpenGlobal(KTestMultithreadStressFinishSemaphore));
sl@0
  2466
	CleanupStack::PushL(TCleanupItem(CleanupFinishSemaphore, &threadFinishSemaphore));
sl@0
  2467
sl@0
  2468
	User::LeaveIfError(RFbsSession::Connect());
sl@0
  2469
	CFbsTypefaceStore* ts = CFbsTypefaceStore::NewL(NULL);
sl@0
  2470
	CleanupStack::PushL(ts);
sl@0
  2471
	
sl@0
  2472
	CFbsFont* font;
sl@0
  2473
	User::LeaveIfError(ts->GetNearestFontToDesignHeightInPixels((CFont*&)font, aParam.iFontSpec));
sl@0
  2474
sl@0
  2475
	TInt numGlyphMatches = 0;
sl@0
  2476
	TInt index = 0;
sl@0
  2477
	TInt err = KErrNone;
sl@0
  2478
	RFbsGlyphDataIterator iter;
sl@0
  2479
	for (err = iter.Open(*font, aParam.iGlyphCodes, aParam.iGlyphCodesCount); err == KErrNone; err = iter.Next(), ++index)
sl@0
  2480
		{
sl@0
  2481
		TBool glyphMatch = EFalse;
sl@0
  2482
		font->GetCharacterData(aParam.iGlyphCodes[index] | KGlyphCodeFlag, charMetrics, bitmapData, bitmapSize);
sl@0
  2483
		if (bitmapSize == TSize(0, 0))
sl@0
  2484
			{
sl@0
  2485
			glyphMatch = (bitmapSize == iter.Rect().Size());
sl@0
  2486
			}
sl@0
  2487
		else
sl@0
  2488
			{
sl@0
  2489
			err = CreateSgImageFromCharacterData(bitmapData, bitmapSize, font->FontSpecInTwips().iFontStyle.BitmapType(), charDataImage);
sl@0
  2490
			if (err == KErrNone)
sl@0
  2491
				{
sl@0
  2492
				err = CompareSgImages(aParam.iEGL, iter.Image(), iter.Rect(), charDataImage, TRect(bitmapSize), glyphMatch);
sl@0
  2493
				}
sl@0
  2494
			charDataImage.Close();
sl@0
  2495
			}
sl@0
  2496
		if (err != KErrNone)
sl@0
  2497
			{
sl@0
  2498
			break;
sl@0
  2499
			}
sl@0
  2500
		numGlyphMatches += (glyphMatch) ? 1 : 0;
sl@0
  2501
		}
sl@0
  2502
	iter.Close();
sl@0
  2503
	
sl@0
  2504
	if (index != aParam.iGlyphCodesCount)
sl@0
  2505
		{
sl@0
  2506
		aStep->ERR_PRINTF5(_L("Thread %d: Iterator terminated early - %d out of %d glyphs (err=%d)"), aThreadNum, index, aParam.iGlyphCodesCount, err);
sl@0
  2507
		aStep->SetTestStepResult(EFail);
sl@0
  2508
		}
sl@0
  2509
	if (index != numGlyphMatches)
sl@0
  2510
		{
sl@0
  2511
		aStep->ERR_PRINTF4(_L("Thread %d: Matched %d out of %d glyphs"), aThreadNum, numGlyphMatches, aParam.iGlyphCodesCount);
sl@0
  2512
		aStep->SetTestStepResult(EFail);
sl@0
  2513
		}
sl@0
  2514
sl@0
  2515
	ts->ReleaseFont(font);
sl@0
  2516
	CleanupStack::PopAndDestroy(2); // ts, threadFinishSemaphore
sl@0
  2517
	RFbsSession::Disconnect();
sl@0
  2518
	}
sl@0
  2519
sl@0
  2520
/**
sl@0
  2521
@SYMTestCaseID      GRAPHICS-FBSERV-0673
sl@0
  2522
@SYMTestPriority    Medium
sl@0
  2523
@SYMTestType        UT
sl@0
  2524
@SYMTestStatus      Implemented
sl@0
  2525
@SYMPREQ            PREQ2678
sl@0
  2526
sl@0
  2527
@SYMTestCaseDesc
sl@0
  2528
    Tests the robustness of using RFbsGlyphMetricsArray when the client heap and the
sl@0
  2529
    FbServ private heap experience failures allocating memory, causing no panics 
sl@0
  2530
    or leaves.
sl@0
  2531
sl@0
  2532
@SYMTestActions
sl@0
  2533
    i. Set the default heap failure for the next heap allocation.
sl@0
  2534
    ii. Create a new CFbsFont using a TFontSpec not already in the glyph atlas.
sl@0
  2535
    iii. Call RFbsGlyphMetricsArray::Get(), and close the array.
sl@0
  2536
    iv. Release the font so that nothing is left in the cache as a result of
sl@0
  2537
        attempting to use it, and reset the heap failure state.
sl@0
  2538
    v. While iii returns KErrNoMemory, increment the failure count and repeat
sl@0
  2539
        step ii.
sl@0
  2540
    vi. Using a separate font so that the test is not affected by the earlier
sl@0
  2541
        run, repeat ii. to v., but rather than setting the default heap to 
sl@0
  2542
        fail, the FbServ private heap is set to fail, via IPC messages to Fbs.
sl@0
  2543
sl@0
  2544
@SYMTestExpectedResults
sl@0
  2545
    If no errors occur, KErrNone should be returned after a certain number of
sl@0
  2546
    repetitions. Any other error code denotes a problem handling low-memory 
sl@0
  2547
    situtations.
sl@0
  2548
*/
sl@0
  2549
void CTFbsGlyphData::TestGlyphMetricsArrayHeapOOML()
sl@0
  2550
    {
sl@0
  2551
    INFO_PRINTF1(_L("Test RFbsGlyphMetricsArray during heap alloc failure"));
sl@0
  2552
    __UHEAP_MARK;
sl@0
  2553
sl@0
  2554
    // Create a font that wont be in the cache already...
sl@0
  2555
    TInt rep = 0;
sl@0
  2556
    TInt err = KErrNoMemory;
sl@0
  2557
    CFbsFont* font = NULL;
sl@0
  2558
    
sl@0
  2559
    while (err == KErrNoMemory)
sl@0
  2560
        {
sl@0
  2561
        User::LeaveIfError(iTs->GetNearestFontInPixels((CFont*&)font, GenerateDejaVuFontSpec(10)));
sl@0
  2562
        __UHEAP_FAILNEXT(rep);
sl@0
  2563
        RFbsGlyphMetricsArray array;
sl@0
  2564
        err = array.Get(*font, iGlyphCodesLatin, KNumGlyphCodesLatin);
sl@0
  2565
        array.Close();
sl@0
  2566
        __UHEAP_RESET;
sl@0
  2567
        iTs->ReleaseFont(font);
sl@0
  2568
        font = NULL;
sl@0
  2569
        ++rep;
sl@0
  2570
        }
sl@0
  2571
sl@0
  2572
	TESTE(err == KErrNone, err);
sl@0
  2573
    if (err == KErrNone)
sl@0
  2574
        {
sl@0
  2575
        INFO_PRINTF2(_L("Client Heap OOM : Test passed after rep %d"), rep);
sl@0
  2576
        }
sl@0
  2577
    else
sl@0
  2578
        {
sl@0
  2579
        ERR_PRINTF3(_L("Client Heap OOM : Test failed with err=%d, after rep %d"), err, rep);
sl@0
  2580
        }
sl@0
  2581
sl@0
  2582
    // Now test when the server-side FbServ heap fails...
sl@0
  2583
    rep = 0;
sl@0
  2584
    err = KErrNoMemory;
sl@0
  2585
    
sl@0
  2586
    while (err == KErrNoMemory)
sl@0
  2587
        {
sl@0
  2588
        User::LeaveIfError(iTs->GetNearestFontInPixels((CFont*&)font, GenerateDejaVuFontSpec(11)));
sl@0
  2589
        iFbs->SendCommand(EFbsMessSetHeapFail, RFbsSession::EHeapFailTypeServerMemory, rep);
sl@0
  2590
        RFbsGlyphMetricsArray array;
sl@0
  2591
        err = array.Get(*font, iGlyphCodesLatin, KNumGlyphCodesLatin);
sl@0
  2592
        array.Close();
sl@0
  2593
        iFbs->SendCommand(EFbsMessSetHeapReset, RFbsSession::EHeapFailTypeServerMemory);
sl@0
  2594
        iTs->ReleaseFont(font);
sl@0
  2595
        font = NULL;
sl@0
  2596
        ++rep;
sl@0
  2597
        }
sl@0
  2598
sl@0
  2599
	TESTE(err == KErrNone, err);
sl@0
  2600
    if (err == KErrNone)
sl@0
  2601
        {
sl@0
  2602
        INFO_PRINTF2(_L("FBServ Heap OOM : Test passed after rep %d"), rep);
sl@0
  2603
        }
sl@0
  2604
    else
sl@0
  2605
        {
sl@0
  2606
        ERR_PRINTF3(_L("FBServ Heap OOM : Test failed with err=%d, after rep %d"), err, rep);      
sl@0
  2607
        }
sl@0
  2608
    __UHEAP_MARKEND;
sl@0
  2609
    }
sl@0
  2610
sl@0
  2611
/**
sl@0
  2612
@SYMTestCaseID      GRAPHICS-FBSERV-0674
sl@0
  2613
@SYMTestPriority    Medium
sl@0
  2614
@SYMTestType        UT
sl@0
  2615
@SYMTestStatus      Implemented
sl@0
  2616
@SYMPREQ            PREQ2678
sl@0
  2617
sl@0
  2618
@SYMTestCaseDesc
sl@0
  2619
    Tests the robustness of using RFbsGlyphDataIterator when the client heap and the
sl@0
  2620
    FbServ private heap experience failures allocating memory, causing no panics 
sl@0
  2621
    or leaves.
sl@0
  2622
sl@0
  2623
@SYMTestActions
sl@0
  2624
    i. Set the default heap failure for the next heap allocation.
sl@0
  2625
    ii. Create a new CFbsFont using a TFontSpec not already in the glyph atlas.
sl@0
  2626
    iii. Call RFbsGlyphDataIterator::Open(), and close the array.
sl@0
  2627
    iv. Release the font so that nothing is left in the cache as a result of
sl@0
  2628
        attempting to use it, and reset the heap failure state.
sl@0
  2629
    v. While iii returns KErrNoMemory, increment the failure count and repeat
sl@0
  2630
        step ii.
sl@0
  2631
    vi. Using a separate font so that the test is not affected by the earlier
sl@0
  2632
        run, repeat ii. to v., but rather than setting the default heap to 
sl@0
  2633
        fail, the FbServ private heap is set to fail, via IPC messages to Fbs.
sl@0
  2634
sl@0
  2635
@SYMTestExpectedResults
sl@0
  2636
    If no errors occur, KErrNone should be returned after a certain number of
sl@0
  2637
    repetitions. Any other error code denotes a problem handling low-memory 
sl@0
  2638
    situtations.
sl@0
  2639
*/
sl@0
  2640
void CTFbsGlyphData::TestGlyphDataIteratorHeapOOML()
sl@0
  2641
    {
sl@0
  2642
    INFO_PRINTF1(_L("Test RFbsGlyphDataIterator during heap alloc failure"));    
sl@0
  2643
    __UHEAP_MARK;
sl@0
  2644
sl@0
  2645
    // Create a font that wont be in the cache already...
sl@0
  2646
    TInt rep = 0;
sl@0
  2647
    TInt err = KErrNoMemory;
sl@0
  2648
    CFbsFont* font = NULL;
sl@0
  2649
    
sl@0
  2650
    while (err == KErrNoMemory)
sl@0
  2651
        {
sl@0
  2652
        User::LeaveIfError(iTs->GetNearestFontInPixels((CFont*&)font, GenerateDejaVuFontSpec(10)));
sl@0
  2653
        __UHEAP_FAILNEXT(rep);
sl@0
  2654
        RFbsGlyphDataIterator iter;
sl@0
  2655
        err = iter.Open(*font, iGlyphCodesLatin, KNumGlyphCodesLatin);
sl@0
  2656
        if (err == KErrNone)
sl@0
  2657
            {
sl@0
  2658
            while (err == KErrNone) 
sl@0
  2659
               {
sl@0
  2660
               err = iter.Next();
sl@0
  2661
               }
sl@0
  2662
            err = (err == KErrNotFound) ? KErrNone : err;
sl@0
  2663
            }
sl@0
  2664
        iter.Close();
sl@0
  2665
        __UHEAP_RESET;
sl@0
  2666
        iTs->ReleaseFont(font);
sl@0
  2667
        font = NULL;
sl@0
  2668
        ++rep;
sl@0
  2669
        }
sl@0
  2670
sl@0
  2671
	TESTE(err == KErrNone, err);
sl@0
  2672
    if (err == KErrNone)
sl@0
  2673
        {
sl@0
  2674
        INFO_PRINTF2(_L("Client Heap OOM : Test passed after rep %d"), rep);
sl@0
  2675
        }
sl@0
  2676
    else
sl@0
  2677
        {
sl@0
  2678
        ERR_PRINTF3(_L("Client Heap OOM : Test failed with err=%d, after rep %d"), err, rep);
sl@0
  2679
        }
sl@0
  2680
sl@0
  2681
    // Now test when the server-side FbServ heap fails...
sl@0
  2682
    rep = 0;
sl@0
  2683
    err = KErrNoMemory;
sl@0
  2684
    
sl@0
  2685
    while (err == KErrNoMemory)
sl@0
  2686
        {
sl@0
  2687
        User::LeaveIfError(iTs->GetNearestFontInPixels((CFont*&)font, GenerateDejaVuFontSpec(11)));
sl@0
  2688
        iFbs->SendCommand(EFbsMessSetHeapFail, RFbsSession::EHeapFailTypeServerMemory, rep);
sl@0
  2689
        RFbsGlyphDataIterator iter;
sl@0
  2690
        err = iter.Open(*font, iGlyphCodesLatin, KNumGlyphCodesLatin);
sl@0
  2691
        if (err == KErrNone)
sl@0
  2692
            {
sl@0
  2693
            while (err == KErrNone) 
sl@0
  2694
               {
sl@0
  2695
               err = iter.Next();
sl@0
  2696
               }
sl@0
  2697
            err = (err == KErrNotFound) ? KErrNone : err;
sl@0
  2698
            }
sl@0
  2699
        iter.Close();
sl@0
  2700
        iFbs->SendCommand(EFbsMessSetHeapReset, RFbsSession::EHeapFailTypeServerMemory);
sl@0
  2701
        iTs->ReleaseFont(font);
sl@0
  2702
        font = NULL;
sl@0
  2703
        ++rep;
sl@0
  2704
        }
sl@0
  2705
sl@0
  2706
	TESTE(err == KErrNone, err);
sl@0
  2707
    if (err == KErrNone)
sl@0
  2708
        {
sl@0
  2709
        INFO_PRINTF2(_L("FBServ Heap OOM : Test passed after rep %d"), rep);
sl@0
  2710
        }
sl@0
  2711
    else
sl@0
  2712
        {
sl@0
  2713
        ERR_PRINTF3(_L("FBServ Heap OOM : Test failed with err=%d, after rep %d"), err, rep);
sl@0
  2714
        }
sl@0
  2715
    __UHEAP_MARKEND;
sl@0
  2716
    }
sl@0
  2717
sl@0
  2718
/**
sl@0
  2719
Utility function. Prints out a description of the font's fontspec to the log.
sl@0
  2720
 */
sl@0
  2721
void CTFbsGlyphData::InfoPrintFontSpec(const CFont& aFont)
sl@0
  2722
	{
sl@0
  2723
	_LIT(KMonochromeBitmap, "Mono");
sl@0
  2724
	_LIT(KAntiAliasedBitmap, "AA");
sl@0
  2725
	_LIT(KStyleItalic, "Italic");
sl@0
  2726
	_LIT(KStyleBold, "Bold");
sl@0
  2727
	_LIT(KStyleNormal, "Normal");
sl@0
  2728
	_LIT(KUnknown, "Unknown");
sl@0
  2729
	TBufC<9> bitmapType;
sl@0
  2730
	TBuf<12> fontStyle;
sl@0
  2731
	TFontSpec fontSpec = aFont.FontSpecInTwips();
sl@0
  2732
	switch(fontSpec.iFontStyle.BitmapType())
sl@0
  2733
		{
sl@0
  2734
		case EMonochromeGlyphBitmap:
sl@0
  2735
			bitmapType = KMonochromeBitmap;
sl@0
  2736
			break;
sl@0
  2737
		case EAntiAliasedGlyphBitmap:
sl@0
  2738
			bitmapType = KAntiAliasedBitmap;
sl@0
  2739
			break;
sl@0
  2740
		default:
sl@0
  2741
			bitmapType = KUnknown;
sl@0
  2742
		}
sl@0
  2743
sl@0
  2744
	if (fontSpec.iFontStyle.StrokeWeight() == EStrokeWeightBold)
sl@0
  2745
		{
sl@0
  2746
		fontStyle.Append(KStyleBold);
sl@0
  2747
		}
sl@0
  2748
	if (fontSpec.iFontStyle.Posture() == EPostureItalic)
sl@0
  2749
		{
sl@0
  2750
		fontStyle.Append(KStyleItalic);
sl@0
  2751
		}
sl@0
  2752
	if (fontStyle.Length() == 0)
sl@0
  2753
		{
sl@0
  2754
		fontStyle = KStyleNormal;
sl@0
  2755
		}
sl@0
  2756
sl@0
  2757
	INFO_PRINTF5(_L("Font: name=%S size=%dtw type=%S style=%S"), &(fontSpec.iTypeface.iName), fontSpec.iHeight, &bitmapType, &fontStyle);
sl@0
  2758
	}
sl@0
  2759
sl@0
  2760
sl@0
  2761
/**
sl@0
  2762
Static utility function. Performs a per-pixel comparison of two open RSgImages.
sl@0
  2763
To do this requires access to the binary data of the images, only accessable
sl@0
  2764
via EGL and Khronos APIs. This function will bind the RSgImages to VGImages 
sl@0
  2765
and uses OpenVG to retrieve the image data in 8bpp.
sl@0
  2766
@param aEGL An EGL Helper to read the SgImages into system memory.
sl@0
  2767
@param aImageA The first image to compare.
sl@0
  2768
@param aRectA A rectangular portion in pixels of the first image to compare.
sl@0
  2769
@param aImageB The second image to compare.
sl@0
  2770
@param aRectB A rectangular portion in pixels fo the second image to compare.
sl@0
  2771
@param aMatch A boolean value, which on return tells the caller whether the two
sl@0
  2772
	images were deemed to match.
sl@0
  2773
@return KErrNone, if the comparison took place, otherwise one of the system-wide
sl@0
  2774
	error codes.
sl@0
  2775
*/
sl@0
  2776
TInt CTFbsGlyphData::CompareSgImages(CEGLHelper* aEGL, const RSgImage& aImageA, const TRect& aRectA, const RSgImage& aImageB, const TRect& aRectB, TBool& aMatch)
sl@0
  2777
	{
sl@0
  2778
	return CTFbsGlyphData::CompareSgImages(aEGL, aImageA, aRectA, NULL, aImageB, aRectB, NULL, aMatch);
sl@0
  2779
	}
sl@0
  2780
sl@0
  2781
/**
sl@0
  2782
Static utility function. Performs a per-pixel comparison of two open RSgImages.
sl@0
  2783
To do this requires access to the binary data of the images, only accessable
sl@0
  2784
via EGL and Khronos APIs. This function will bind the RSgImages to VGImages 
sl@0
  2785
and uses OpenVG to retrieve the image data in 8bpp.
sl@0
  2786
This version allows pre-created memory to be used in the comparison, to avoid
sl@0
  2787
allocation failure in low memory testing.
sl@0
  2788
@param aEGL An EGL Helper to read the SgImages into system memory buffers.
sl@0
  2789
@param aImageA The first image to compare.
sl@0
  2790
@param aRectA A rectangular portion in pixels of the first image to compare.
sl@0
  2791
@param aBufferA If non-NULL, specifies a memory buffer to read the data of
sl@0
  2792
	aImageA into, otherwise a buffer is dynamically allocated.
sl@0
  2793
@param aImageB The second image to compare.
sl@0
  2794
@param aRectB A rectangular portion in pixels fo the second image to compare.
sl@0
  2795
@param aBufferB If non-NULL, specifies a memory buffer to read the data of
sl@0
  2796
	aImageB into, otherwise a buffer is dynamically allocated.
sl@0
  2797
@param aMatch A boolean value, which on return tells the caller whether the two
sl@0
  2798
	images were deemed to match.
sl@0
  2799
@return KErrNone, if the comparison took place, otherwise one of the system-wide
sl@0
  2800
	error codes.
sl@0
  2801
*/
sl@0
  2802
TInt CTFbsGlyphData::CompareSgImages(CEGLHelper* aEGL, const RSgImage& aImageA, const TRect& aRectA, TUint8* aBufferA, const RSgImage& aImageB, const TRect& aRectB, TUint8* aBufferB, TBool& aMatch)
sl@0
  2803
	{
sl@0
  2804
	// By default, assume they do not match.
sl@0
  2805
	aMatch = EFalse;
sl@0
  2806
	
sl@0
  2807
#ifdef SAVEGLYPHSTOMBMDURINGCOMPARISON
sl@0
  2808
	
sl@0
  2809
	static TInt countToAppend = 0;
sl@0
  2810
	
sl@0
  2811
	CFbsBitmap* bitmap = NULL;
sl@0
  2812
	if (KErrNone == CreateBitmapFromSgImage(aEGL, aImageA, aRectA, bitmap))
sl@0
  2813
		{
sl@0
  2814
		TBuf<KMaxFileName> buf;
sl@0
  2815
		buf.AppendNum( countToAppend );
sl@0
  2816
		TPtrC nameAppend( buf );
sl@0
  2817
		
sl@0
  2818
		SaveBmp(bitmap, &nameAppend, EFalse);
sl@0
  2819
		}
sl@0
  2820
	delete bitmap;	
sl@0
  2821
	if (KErrNone == CreateBitmapFromSgImage(aEGL, aImageB, aRectB, bitmap))
sl@0
  2822
		{
sl@0
  2823
		TBuf<KMaxFileName> buf;
sl@0
  2824
		buf.AppendNum( countToAppend );
sl@0
  2825
		TPtrC nameAppend( buf );
sl@0
  2826
	
sl@0
  2827
		SaveBmp(bitmap, &nameAppend, ETrue);
sl@0
  2828
		}
sl@0
  2829
	delete bitmap;
sl@0
  2830
	
sl@0
  2831
	countToAppend++;
sl@0
  2832
	
sl@0
  2833
#endif // SAVEGLYPHSTOMBMDURINGCOMPARISON
sl@0
  2834
	
sl@0
  2835
	TSgImageInfo imageInfoA;
sl@0
  2836
	TSgImageInfo imageInfoB;
sl@0
  2837
	if (aImageA.GetInfo(imageInfoA) != KErrNone ||
sl@0
  2838
		aImageB.GetInfo(imageInfoB) != KErrNone)
sl@0
  2839
		{
sl@0
  2840
		return KErrBadHandle;
sl@0
  2841
		}
sl@0
  2842
		
sl@0
  2843
	// Check the sizes of the images match, and the rects reside on the images.
sl@0
  2844
	if (aRectA.Size() != aRectB.Size() ||
sl@0
  2845
		!TRect(imageInfoA.iSizeInPixels).Intersects(aRectA) ||
sl@0
  2846
		!TRect(imageInfoB.iSizeInPixels).Intersects(aRectB))
sl@0
  2847
		{
sl@0
  2848
		return KErrNone;		
sl@0
  2849
		}
sl@0
  2850
	const TSize KBufferSize = aRectA.Size();
sl@0
  2851
	const TInt KDataStride = KBufferSize.iWidth;
sl@0
  2852
sl@0
  2853
	TBool freeTempBufA = EFalse;
sl@0
  2854
	TBool freeTempBufB = EFalse;
sl@0
  2855
	if (!aBufferA)
sl@0
  2856
		{
sl@0
  2857
		aBufferA = (TUint8*) User::AllocZ(KDataStride * KBufferSize.iHeight);
sl@0
  2858
		freeTempBufA = ETrue;
sl@0
  2859
		}
sl@0
  2860
	if (!aBufferA)
sl@0
  2861
		{
sl@0
  2862
		return KErrNoMemory;
sl@0
  2863
		}
sl@0
  2864
	TInt err = aEGL->GetSgImageData(aImageA, aRectA, aBufferA);
sl@0
  2865
	if (err != KErrNone)
sl@0
  2866
		{
sl@0
  2867
		if (freeTempBufA)
sl@0
  2868
			{
sl@0
  2869
			User::Free(aBufferA);
sl@0
  2870
			aBufferA = NULL;
sl@0
  2871
			}
sl@0
  2872
		return err;
sl@0
  2873
		}
sl@0
  2874
	if (!aBufferB)
sl@0
  2875
		{
sl@0
  2876
		aBufferB = (TUint8*) User::AllocZ(KDataStride * KBufferSize.iHeight);
sl@0
  2877
		freeTempBufB = ETrue;
sl@0
  2878
		}
sl@0
  2879
	if (!aBufferB)
sl@0
  2880
		{
sl@0
  2881
		if (freeTempBufA)
sl@0
  2882
			{
sl@0
  2883
			User::Free(aBufferA);
sl@0
  2884
			aBufferA = NULL;
sl@0
  2885
			}
sl@0
  2886
		return KErrNoMemory;
sl@0
  2887
		}
sl@0
  2888
	err = aEGL->GetSgImageData(aImageB, aRectB, aBufferB);
sl@0
  2889
	if (err != KErrNone)
sl@0
  2890
		{
sl@0
  2891
		if (freeTempBufA)
sl@0
  2892
			{
sl@0
  2893
			User::Free(aBufferA);
sl@0
  2894
			aBufferA = NULL;
sl@0
  2895
			}
sl@0
  2896
		if (freeTempBufB)
sl@0
  2897
			{
sl@0
  2898
			User::Free(aBufferB);
sl@0
  2899
			aBufferB = NULL;
sl@0
  2900
			}
sl@0
  2901
		return err;
sl@0
  2902
		}	
sl@0
  2903
sl@0
  2904
	// Perform a per-pixel comparison, scanline by scanline.
sl@0
  2905
	// The loop will break as soon as a mismatch is detected.
sl@0
  2906
	aMatch = ETrue;
sl@0
  2907
	for (TInt scanline = 0; (scanline < KBufferSize.iHeight) && aMatch; ++scanline)
sl@0
  2908
		{
sl@0
  2909
		TUint8* scanlineImageA = aBufferA + (scanline * KDataStride);
sl@0
  2910
		TUint8* scanlineImageB = aBufferB + (scanline * KDataStride);
sl@0
  2911
		aMatch = (Mem::Compare(scanlineImageA, KBufferSize.iWidth, scanlineImageB, KBufferSize.iWidth) == 0);
sl@0
  2912
		}
sl@0
  2913
sl@0
  2914
	if (freeTempBufA)
sl@0
  2915
		{
sl@0
  2916
		User::Free(aBufferA);
sl@0
  2917
		aBufferA = NULL;
sl@0
  2918
		}
sl@0
  2919
	if (freeTempBufB)
sl@0
  2920
		{
sl@0
  2921
		User::Free(aBufferB);
sl@0
  2922
		aBufferB = NULL;
sl@0
  2923
		}
sl@0
  2924
	
sl@0
  2925
	return KErrNone;
sl@0
  2926
	}
sl@0
  2927
sl@0
  2928
/**
sl@0
  2929
Second thread entry function for multi-threaded tests.
sl@0
  2930
*/
sl@0
  2931
TInt CTFbsGlyphData::ThreadFunction(TAny* aParam)
sl@0
  2932
	{
sl@0
  2933
	__UHEAP_MARK;
sl@0
  2934
	CTrapCleanup* cleanupStack = CTrapCleanup::New();
sl@0
  2935
	if (!cleanupStack)
sl@0
  2936
		{
sl@0
  2937
		return KErrNoMemory;
sl@0
  2938
		}
sl@0
  2939
sl@0
  2940
	TGlyphDataThreadInfo* info = static_cast<TGlyphDataThreadInfo*>(aParam);
sl@0
  2941
	TRAPD(result,
sl@0
  2942
	switch(info->iTest)
sl@0
  2943
		{
sl@0
  2944
		case EGlyphDataMultiSessionTestShareGlyphs:
sl@0
  2945
			CTFbsGlyphData::ThreadShareGlyphsL(info->iThreadNum, info->iParams, info->iStep);
sl@0
  2946
			break;
sl@0
  2947
		case EGlyphDataMultiSessionTestStressAtlas:
sl@0
  2948
			CTFbsGlyphData::ThreadStressAtlasL(info->iThreadNum, info->iParams, info->iStep);
sl@0
  2949
			break;
sl@0
  2950
		default:
sl@0
  2951
			User::Leave(KErrArgument);
sl@0
  2952
		}
sl@0
  2953
	);
sl@0
  2954
sl@0
  2955
	delete cleanupStack;
sl@0
  2956
	__UHEAP_MARKEND;
sl@0
  2957
	return result;
sl@0
  2958
	}
sl@0
  2959
sl@0
  2960
sl@0
  2961
sl@0
  2962
/*
sl@0
  2963
	-----------------------------------------
sl@0
  2964
	Static utility Methods used by the tests.
sl@0
  2965
	-----------------------------------------
sl@0
  2966
*/
sl@0
  2967
sl@0
  2968
sl@0
  2969
sl@0
  2970
/**
sl@0
  2971
Utility method that fills the RSgImage memory with RSgImages until either KErrNoMemory
sl@0
  2972
or KErrNoGraphicsMemory is returned.
sl@0
  2973
sl@0
  2974
@param aSize The size of the image used to fill the graphics memory - a form of granularity
sl@0
  2975
@param aImages Returns the array of the images used to fill the graphics memory.
sl@0
  2976
@return KErrNoGraphicsMemory or KErrNoMemory if successful, otherwise one of the system
sl@0
  2977
	wide error codes.
sl@0
  2978
 */
sl@0
  2979
/*static TInt FillGraphicsMemoryWithImages(const TSize& aSize, RArray<RSgImage>& aImages)
sl@0
  2980
	{
sl@0
  2981
	TInt err = KErrNone;
sl@0
  2982
	while (KErrNone == err)
sl@0
  2983
		{
sl@0
  2984
		RSgImage sgImage;
sl@0
  2985
		err = sgImage.Create(TSgImageInfo(aSize, ESgPixelFormatA_8, ESgUsageBitOpenVgImage));
sl@0
  2986
		if (KErrNone == err)
sl@0
  2987
			{
sl@0
  2988
			err = aImages.Append(sgImage);
sl@0
  2989
			}
sl@0
  2990
		}
sl@0
  2991
	return err;
sl@0
  2992
	}*/
sl@0
  2993
sl@0
  2994
/**
sl@0
  2995
Utility method that fills the RSgImage memory with RSgImages until either KErrNoMemory
sl@0
  2996
or KErrNoGraphicsMemory is returned and then closes one RSgImage to free up some memory.
sl@0
  2997
sl@0
  2998
@param aSize The size of the image used to fill the graphics memory - a form of granularity
sl@0
  2999
@param aImages Returns the array of the images used to fill the graphics memory.
sl@0
  3000
@return KErrNone if successful, otherwise one of the system	wide error codes.
sl@0
  3001
 */
sl@0
  3002
/*static TInt NearlyFillGraphicsMemoryWithImages(const TSize& aSize, RArray<RSgImage>& aImages)
sl@0
  3003
	{
sl@0
  3004
	TInt err = FillGraphicsMemoryWithImages(aSize, aImages);
sl@0
  3005
	if (err == KErrNoMemory || err == KErrNoGraphicsMemory)
sl@0
  3006
		{
sl@0
  3007
		if (aImages.Count() > 0)
sl@0
  3008
			{
sl@0
  3009
			// Remove an image to free up some memory.
sl@0
  3010
			TInt lastIndex = aImages.Count() - 1;
sl@0
  3011
			aImages[lastIndex].Close();
sl@0
  3012
			aImages.Remove(lastIndex);
sl@0
  3013
			}
sl@0
  3014
		err = KErrNone;
sl@0
  3015
		}
sl@0
  3016
	return err;
sl@0
  3017
	}*/
sl@0
  3018
sl@0
  3019
/**
sl@0
  3020
Static utility function. Creates an 8bpp RSgImage from 1bpp or 8bpp character
sl@0
  3021
data, with VGImage usage flag set.
sl@0
  3022
@param aData The character image data. Either in 8bpp or 1bpp RLE format.
sl@0
  3023
@param aSize The size of the character image in pixels.
sl@0
  3024
@param aType The type of glyph - Monochrome or Antialiased. 
sl@0
  3025
@param aSgImage A closed image which will be populated with 8bpp image data.
sl@0
  3026
*/
sl@0
  3027
static TInt CreateSgImageFromCharacterData(const TUint8* aData, const TSize& aSize, TGlyphBitmapType aType, RSgImage& aImage)
sl@0
  3028
	{
sl@0
  3029
	return CreateSgImageFromCharacterData(aData, aSize, aType, aImage, NULL, NULL);
sl@0
  3030
	}
sl@0
  3031
sl@0
  3032
/**
sl@0
  3033
Static utility function. Creates an 8bpp RSgImage from 1bpp or 8bpp character
sl@0
  3034
data, with VGImage usage flag set. 
sl@0
  3035
This overload allows the memory for the buffers to be pre-created to avoid
sl@0
  3036
memory allocation failure during low-memory testing.
sl@0
  3037
@param aData The character image data. Either in 8bpp or 1bpp RLE format.
sl@0
  3038
@param aSize The size of the character image in pixels.
sl@0
  3039
@param aType The type of glyph - Monochrome or Antialiased. 
sl@0
  3040
@param aSgImage A closed image which will be populated with 8bpp image data.
sl@0
  3041
@param aBuffer1 If non-NULL, used as a memory buffer for reading the decoded 
sl@0
  3042
	image data into for monochrome images.
sl@0
  3043
@param aBuffer2 If non-NULL, used as a memory buffer for the decoded image
sl@0
  3044
	data for monochrome images.
sl@0
  3045
*/
sl@0
  3046
static TInt CreateSgImageFromCharacterData(const TUint8* aData, const TSize& aSize, TGlyphBitmapType aType, RSgImage& aImage, TUint8* aBuffer1, TUint8* aBuffer2)
sl@0
  3047
	{
sl@0
  3048
	TInt err = KErrNone;	
sl@0
  3049
	if (aSize == TSize(0, 0))
sl@0
  3050
		{
sl@0
  3051
		return KErrArgument;
sl@0
  3052
		}
sl@0
  3053
	TUint8* dataBuf = NULL;
sl@0
  3054
	TInt dataStride = 0;
sl@0
  3055
	TBool freeDataBuf = EFalse;
sl@0
  3056
	if (aType == EAntiAliasedGlyphBitmap)
sl@0
  3057
		{
sl@0
  3058
		dataBuf = const_cast<TUint8*>(aData);
sl@0
  3059
		dataStride = aSize.iWidth;
sl@0
  3060
		}
sl@0
  3061
	else if (aType == EMonochromeGlyphBitmap)
sl@0
  3062
		{
sl@0
  3063
		TUint8* binaryData = NULL;
sl@0
  3064
		TUint8* tempBuf = NULL;
sl@0
  3065
		TInt binaryDataStride = ((aSize.iWidth + 31) / 32) << 2;
sl@0
  3066
		TInt binaryDataSize = binaryDataStride * aSize.iHeight;
sl@0
  3067
		if (aBuffer1 && User::AllocLen(aBuffer1) >= binaryDataSize)
sl@0
  3068
			{
sl@0
  3069
			binaryData = aBuffer1;
sl@0
  3070
			}
sl@0
  3071
		else
sl@0
  3072
			{
sl@0
  3073
			tempBuf = (TUint8*) User::AllocZ(binaryDataSize);
sl@0
  3074
			if (!tempBuf)
sl@0
  3075
				{
sl@0
  3076
				return KErrNoMemory;
sl@0
  3077
				}
sl@0
  3078
			binaryData = tempBuf;
sl@0
  3079
			}
sl@0
  3080
		// Unpack the run length encoded data into 1bpp
sl@0
  3081
		DecodeBinaryData(aSize, aData, binaryDataStride, reinterpret_cast<TUint32*&>(binaryData));
sl@0
  3082
		dataStride = aSize.iWidth;
sl@0
  3083
		TInt byteDataSize = dataStride * aSize.iHeight;
sl@0
  3084
		TUint8* byteData = NULL;
sl@0
  3085
		// If aByteBuf supplied, use that instead of allocating a new buffer here.
sl@0
  3086
		if (aBuffer2 && User::AllocLen(aBuffer2) >= byteDataSize)
sl@0
  3087
			{
sl@0
  3088
			byteData = aBuffer2;
sl@0
  3089
			}
sl@0
  3090
		else
sl@0
  3091
			{
sl@0
  3092
			byteData = (TUint8*) User::AllocZ(byteDataSize);
sl@0
  3093
			if (!byteData)
sl@0
  3094
				{
sl@0
  3095
				User::Free(tempBuf);
sl@0
  3096
				return KErrNoMemory;
sl@0
  3097
				}
sl@0
  3098
			freeDataBuf = ETrue;
sl@0
  3099
			}
sl@0
  3100
		dataBuf = byteData;
sl@0
  3101
		for (TInt scanline = 0; scanline < aSize.iHeight; ++scanline)
sl@0
  3102
			{
sl@0
  3103
			TUint8* srcByte = binaryData;
sl@0
  3104
			for (TInt pixel = 0; pixel < aSize.iWidth; pixel++)
sl@0
  3105
				{
sl@0
  3106
				*(byteData+pixel) = ((*srcByte & (1 << (pixel % 8))) == 0) ? 0 : 0xFF;
sl@0
  3107
				if (((pixel + 1) % 8) == 0) srcByte++;
sl@0
  3108
				}
sl@0
  3109
			byteData += dataStride;
sl@0
  3110
			binaryData += binaryDataStride;
sl@0
  3111
			}
sl@0
  3112
		User::Free(tempBuf);
sl@0
  3113
		}
sl@0
  3114
	else
sl@0
  3115
		{
sl@0
  3116
		return KErrArgument;
sl@0
  3117
		}
sl@0
  3118
sl@0
  3119
	// Create RSgImage from CFbsBitmap.
sl@0
  3120
	TSgImageInfo sgImageInfo(aSize, ESgPixelFormatA_8, ESgUsageBitOpenVgImage);
sl@0
  3121
	err = aImage.Create(sgImageInfo, dataBuf, dataStride);
sl@0
  3122
	if (freeDataBuf)
sl@0
  3123
		{
sl@0
  3124
		User::Free(dataBuf);
sl@0
  3125
		}
sl@0
  3126
	return err;
sl@0
  3127
	}
sl@0
  3128
sl@0
  3129
sl@0
  3130
/**
sl@0
  3131
Static utility function, Copies image data line(s) to a destination.
sl@0
  3132
@param aBinaryDataPtr pointer to a destination buffer.
sl@0
  3133
@param aBufferWords Stride of the image.
sl@0
  3134
@param aData Pointer to a source buffer.
sl@0
  3135
@param aBitShift Number of bits, binary data will be shifted. 
sl@0
  3136
@param aCharWidth Width of the image.
sl@0
  3137
@param aRepeatCount Number of lines to copy.
sl@0
  3138
*/
sl@0
  3139
static void CopyCharLine(TUint32*& aBinaryDataPtr,TInt aBufferWords,const TUint8* aData,TInt aBitShift,TInt aCharWidth, TInt16 aRepeatCount)
sl@0
  3140
	{
sl@0
  3141
	aBitShift&=7;
sl@0
  3142
	TInt wordstocopy=(aCharWidth+31)>>5;
sl@0
  3143
	if(wordstocopy>aBufferWords) wordstocopy=aBufferWords;
sl@0
  3144
	TUint32* ptrlimit=aBinaryDataPtr+wordstocopy;
sl@0
  3145
	TUint32* dataword=(TUint32*)(TInt(aData)&~3);
sl@0
  3146
	aBitShift+=(TInt(aData)-TInt(dataword))<<3;
sl@0
  3147
	
sl@0
  3148
	TUint32* startBinaryDataPtr = aBinaryDataPtr;
sl@0
  3149
	while(aBinaryDataPtr<ptrlimit)
sl@0
  3150
		{
sl@0
  3151
		*aBinaryDataPtr=*dataword++;
sl@0
  3152
		*aBinaryDataPtr>>=aBitShift;
sl@0
  3153
		if(aBitShift) *aBinaryDataPtr|=(*dataword<<(32-aBitShift));
sl@0
  3154
		aBinaryDataPtr++;
sl@0
  3155
		}
sl@0
  3156
	
sl@0
  3157
	TUint32* curStartBinaryDataPtr = aBinaryDataPtr;
sl@0
  3158
	TInt byteToCopy = wordstocopy << 2;
sl@0
  3159
	while(aRepeatCount > 1)
sl@0
  3160
		{
sl@0
  3161
		Mem::Copy(curStartBinaryDataPtr, startBinaryDataPtr, byteToCopy);
sl@0
  3162
		curStartBinaryDataPtr += wordstocopy;
sl@0
  3163
		
sl@0
  3164
		aRepeatCount--;
sl@0
  3165
		}
sl@0
  3166
	aBinaryDataPtr = curStartBinaryDataPtr;
sl@0
  3167
	}
sl@0
  3168
sl@0
  3169
/**
sl@0
  3170
Static utility function. Decodes a monochrome glyph whose data is run length encoded, 
sl@0
  3171
into a 1bpp bitmap.
sl@0
  3172
@param aDataSize Image size in pixels.
sl@0
  3173
@param aData Pointer to a source buffer.
sl@0
  3174
@param aStride Image data stride.
sl@0
  3175
@param aBinaryData Pointer to a destination buffer. This buffer must be allocated 
sl@0
  3176
	by the caller.
sl@0
  3177
*/
sl@0
  3178
static void DecodeBinaryData(const TSize& aDataSize, const TUint8* aData, TInt aStride,
sl@0
  3179
											TUint32* aBinaryData)
sl@0
  3180
	{
sl@0
  3181
	const TInt datalength = aDataSize.iWidth;
sl@0
  3182
	const TInt dataheight = aDataSize.iHeight;
sl@0
  3183
	TInt bitindex=0;
sl@0
  3184
	TInt16 repeatcount=0;
sl@0
  3185
	TUint32* slbuffer=aBinaryData;
sl@0
  3186
	const TInt slwords=aStride;
sl@0
  3187
sl@0
  3188
	for(TInt charline=0;charline<dataheight;charline+=repeatcount) // for lines in the character...
sl@0
  3189
		{
sl@0
  3190
		repeatcount=CFbsBitGc::Load16(aData+(bitindex>>3));
sl@0
  3191
		repeatcount>>=bitindex&7;
sl@0
  3192
		const TInt multilineflag=repeatcount&1;
sl@0
  3193
		repeatcount>>=1;
sl@0
  3194
		repeatcount&=0xf;
sl@0
  3195
		bitindex+=5;
sl@0
  3196
		if(multilineflag)
sl@0
  3197
			{
sl@0
  3198
			for(TInt currentline=0;currentline<repeatcount;currentline++)
sl@0
  3199
				{
sl@0
  3200
				CopyCharLine(slbuffer,slwords,aData+(bitindex>>3),bitindex&7,datalength, 1);
sl@0
  3201
				bitindex+=datalength;
sl@0
  3202
				}
sl@0
  3203
			}
sl@0
  3204
		else
sl@0
  3205
			{
sl@0
  3206
			CopyCharLine(slbuffer,slwords,aData+(bitindex>>3),bitindex&7,datalength, repeatcount);
sl@0
  3207
			bitindex+=datalength;
sl@0
  3208
			}
sl@0
  3209
		}
sl@0
  3210
	}
sl@0
  3211
//--------------
sl@0
  3212
__CONSTRUCT_STEP__(FbsGlyphData)