1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/graphics/fbs/fontandbitmapserver/tfbs/tfbsglyphdata.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,3212 @@
1.4 +// Copyright (c) 2009-2010 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +//
1.18 +
1.19 +/**
1.20 + @file
1.21 + @internalComponent - Internal Symbian test code
1.22 +*/
1.23 +
1.24 +#include <test/graphicsfontutils.h>
1.25 +#include <EGL/egl.h>
1.26 +#include <VG/openvg.h>
1.27 +#include <graphics/fbsglyphmetricsarray.h>
1.28 +#include <graphics/fbsglyphdataiterator.h>
1.29 +#include <sgresource/sgimage.h>
1.30 +#include <sgresource/sgdriver_test.h>
1.31 +#include <sgresource/sgdriver_profiling.h>
1.32 +#include "FbsMessage.h"
1.33 +#include "tfbsglyphdata.h"
1.34 +
1.35 +_LIT(KTypefaceName, "DejaVu Sans Condensed");
1.36 +//_LIT(KMonoTypefaceName, "DejaVu Sans Mono");
1.37 +const TInt KNumGlyphCodesLatin = 96;
1.38 +const TUint KDejaVuInvalidGlyphCode = 0;
1.39 +
1.40 +// Currently only used in debug. When TestMultithreadStressAtlas() test is enabled, #ifdef to be removed.
1.41 +#ifdef _DEBUG
1.42 +const TInt KTestThreadMinHeapSize = 0x20000;
1.43 +const TInt KTestThreadMaxHeapSize = 0x20000;
1.44 +#endif
1.45 +
1.46 +// 'most significant bit' flag to ensure value is interpreted as a glyph code rather than an ascii code
1.47 +const TUint KGlyphCodeFlag = 0x80000000;
1.48 +
1.49 +
1.50 +// Please note the following macros which enable helper functions, and are declared in the header.
1.51 +// SAVEGLYPHSTOMBMDURINGCOMPARISON and
1.52 +// SAVEGLYPHSTOMBMDEBUGFUNCTION
1.53 +
1.54 +// Utility function declarations - utilities used by the tests
1.55 +static TFontSpec GenerateDejaVuFontSpec(TInt aSeed);
1.56 +static void CopyCharLine(TUint32*& aBinaryDataPtr,TInt aBufferWords,const TUint8* aData,TInt aBitShift,TInt aCharWidth, TInt16 aRepeatCount);
1.57 +static void DecodeBinaryData(const TSize& aDataSize, const TUint8* aData, TInt aStride, TUint32* aBinaryData);
1.58 +static TInt CreateSgImageFromCharacterData(const TUint8* aData, const TSize& aSize, TGlyphBitmapType aType, RSgImage& aImage);
1.59 +static TInt CreateSgImageFromCharacterData(const TUint8* aData, const TSize& aSize, TGlyphBitmapType aType, RSgImage& aImage, TUint8* aBuffer1, TUint8* aBuffer2);
1.60 +// Following functions commented out because the tests which use these functions
1.61 +// are currently commented out due to Broadcom defect
1.62 +// ESLM-85LDV7 - TB10.1 Closing of RSgImage with duplicate handle used in same thread does not release GPU RAM
1.63 +//static TInt FillGraphicsMemoryWithImages(const TSize& aSize, RArray<RSgImage>& aImages);
1.64 +//static TInt NearlyFillGraphicsMemoryWithImages(const TSize& aSize, RArray<RSgImage>& aImages);
1.65 +
1.66 +#if defined (SAVEGLYPHSTOMBMDEBUGFUNCTION) || defined (SAVEGLYPHSTOMBMDURINGCOMPARISON)
1.67 +/**
1.68 +Static utility function. Converts an A8 RSgImage into a CFbsBitmap.
1.69 +To do this, the RSgImage is converted to an EGLImage, then to a VGImage,
1.70 +where the image memory is read into a CFbsBitmap.
1.71 +
1.72 +@param aEGL The EGL helper object that will read the SgImage into a memory buffer.
1.73 +@param aSgImage The RSgImage to convert.
1.74 +@param aRect A rectangular region of the RSgImage to convert.
1.75 +@param aBitmap On success, holds a pointer to a CFbsBitmap which contains the image
1.76 + data of the RSgImage.
1.77 +@return One of the system-wide error codes.
1.78 +*/
1.79 +static TInt CreateBitmapFromSgImage(CEGLHelper* aEGL, const RSgImage& aSgImage, const TRect& aRect, CFbsBitmap*& aBitmap)
1.80 + {
1.81 + TInt err = KErrNone;
1.82 + const TSize bufferSize = aRect.Size();
1.83 + const TInt dataStride = bufferSize.iWidth;
1.84 +
1.85 + TUint8* imageBuffer = reinterpret_cast<TUint8*>(User::AllocZ(bufferSize.iHeight * dataStride));
1.86 + if (!imageBuffer)
1.87 + {
1.88 + return KErrNoMemory;
1.89 + }
1.90 + err = aEGL->GetSgImageData(aSgImage, aRect, imageBuffer);
1.91 + if (err != KErrNone)
1.92 + {
1.93 + User::Free(imageBuffer);
1.94 + return err;
1.95 + }
1.96 + aBitmap = new CFbsBitmap();
1.97 + if (!aBitmap)
1.98 + {
1.99 + User::Free(imageBuffer);
1.100 + return KErrNoMemory;
1.101 + }
1.102 +
1.103 + err = aBitmap->Create(bufferSize, EGray256);
1.104 + if (KErrNone == err)
1.105 + {
1.106 + TUint8* buf = imageBuffer;
1.107 + aBitmap->BeginDataAccess();
1.108 + TUint8* dataAddress = reinterpret_cast<TUint8*>(aBitmap->DataAddress());
1.109 + const TInt dataStride = aBitmap->DataStride();
1.110 + for (TInt scanline = 0; scanline < bufferSize.iHeight; scanline++)
1.111 + {
1.112 + Mem::Copy(dataAddress, buf, bufferSize.iWidth);
1.113 + dataAddress += dataStride;
1.114 + buf += bufferSize.iWidth;
1.115 + }
1.116 + aBitmap->EndDataAccess(EFalse);
1.117 + }
1.118 + else
1.119 + {
1.120 + delete aBitmap;
1.121 + aBitmap = NULL;
1.122 + }
1.123 +
1.124 + User::Free(imageBuffer);
1.125 + return err;
1.126 + }
1.127 +
1.128 +/**
1.129 +Utility function to aid with debugging.
1.130 +Saves a bitmap to file.
1.131 +
1.132 +@param aBmp Bitmap to save
1.133 +@param aMeta Optional. If specified, it is added to the name of the bitmap file.
1.134 +@param aRef Flag to show whether bitmap is a reference bitmap (ETrue) or test bitmap (EFalse).
1.135 +*/
1.136 +static void SaveBmp(CFbsBitmap* aBmp, TPtrC* aMeta, TBool aRef)
1.137 + {
1.138 + if (!aBmp)
1.139 + {
1.140 + return;
1.141 + }
1.142 +
1.143 + TBuf<256> testFileName;
1.144 + if (aRef)
1.145 + {
1.146 + testFileName.Append(_L("Ref"));
1.147 + }
1.148 + else
1.149 + {
1.150 + testFileName.Append(_L("Test"));
1.151 + }
1.152 + if (aMeta)
1.153 + {
1.154 + testFileName.Append(*aMeta);
1.155 + }
1.156 +
1.157 + TFileName mbmFile;
1.158 + TBuf<20> testPathName;
1.159 + #ifdef __WINS__
1.160 + testPathName.Append(_L("c:\\%S.mbm"));
1.161 + #else
1.162 + testPathName.Append(_L("e:\\%S.mbm"));
1.163 + #endif
1.164 + mbmFile.Format(testPathName, &testFileName);
1.165 +
1.166 + // As this is for debugging purposes only, doesn't matter reporting whether
1.167 + // saving succeeded or not.
1.168 + aBmp->Save(mbmFile);
1.169 + }
1.170 +#endif // SAVEGLYPHSTOMBMDEBUGFUNCTION OR SAVEGLYPHSTOMBMDURINGCOMPARISON
1.171 +
1.172 +
1.173 +#ifdef SAVEGLYPHSTOMBMDEBUGFUNCTION
1.174 +void CTFbsGlyphData::SaveRSgImagesAsMbms(CEGLHelper* aEGL, const RSgImage& aImageA, const TRect& aRectA, const RSgImage& aImageB, const TRect& aRectB )
1.175 + {
1.176 + static TInt countToAppend = 0;
1.177 +
1.178 + CFbsBitmap* bitmap = NULL;
1.179 + if (KErrNone == CreateBitmapFromSgImage(aEGL, aImageA, aRectA, bitmap))
1.180 + {
1.181 + TBuf<KMaxFileName> buf( _L("String") );
1.182 + buf.AppendNum( countToAppend );
1.183 + TPtrC nameAppend( buf );
1.184 +
1.185 + SaveBmp(bitmap, &nameAppend, EFalse);
1.186 + }
1.187 + delete bitmap;
1.188 + bitmap = NULL;
1.189 +
1.190 + if (KErrNone == CreateBitmapFromSgImage(aEGL, aImageB, aRectB, bitmap))
1.191 + {
1.192 + TBuf<KMaxFileName> buf( _L("String") );
1.193 + buf.AppendNum( countToAppend );
1.194 + TPtrC nameAppend( buf );
1.195 +
1.196 + SaveBmp(bitmap, &nameAppend, ETrue);
1.197 + }
1.198 + delete bitmap;
1.199 + bitmap = NULL;
1.200 +
1.201 + countToAppend++;
1.202 + }
1.203 +
1.204 +/**
1.205 +Static debug utility method that outputs the glyph images of the given glyph
1.206 +codes for the given font to a file.
1.207 + */
1.208 +static void DumpFontGlyphs(CEGLHelper* aEGL, CFont* aFont, TInt aCodesCount)
1.209 + {
1.210 + TFontSpec fontSpec = aFont->FontSpecInTwips();
1.211 + TOpenFontCharMetrics charMetrics;
1.212 + TSize bitmapSize;
1.213 + const TUint8* bitmapData = NULL;
1.214 +
1.215 + for (TInt glyphCode = 0; glyphCode < aCodesCount; glyphCode++)
1.216 + {
1.217 + CFont::TCharacterDataAvailability availability = aFont->GetCharacterData(glyphCode | KGlyphCodeFlag, charMetrics, bitmapData, bitmapSize);
1.218 + if (availability == CFont::EAllCharacterData)
1.219 + {
1.220 + RSgImage characterDataImage;
1.221 + TInt err = CreateSgImageFromCharacterData(bitmapData, bitmapSize, fontSpec.iFontStyle.BitmapType(), characterDataImage);
1.222 + if (err == KErrNone)
1.223 + {
1.224 + CFbsBitmap* bitmap = NULL;
1.225 + err = CreateBitmapFromSgImage(aEGL, characterDataImage, TRect(TPoint(0, 0), bitmapSize), bitmap);
1.226 + if (err == KErrNone)
1.227 + {
1.228 + TBuf<256> bitmapName;
1.229 + bitmapName.AppendFormat(_L("%S-%i"), &(fontSpec.iTypeface.Name()), glyphCode);
1.230 + TPtrC bitmapNamePtr(bitmapName);
1.231 + SaveBmp(bitmap, &bitmapNamePtr, EFalse);
1.232 + delete bitmap;
1.233 + }
1.234 + }
1.235 + characterDataImage.Close();
1.236 + }
1.237 + }
1.238 + }
1.239 +#endif // SAVEGLYPHSTOMBMDEBUGFUNCTION
1.240 +
1.241 +
1.242 +/**
1.243 +Utility to return a fontspec such that the font created from it will
1.244 +not match any other font generated by a different seed. The font
1.245 +will be useable by RFbsGlyphDataIterator and RFbsGlyphMetricsArray.
1.246 +It will always return a font based on the DejaVu fontspec, this is
1.247 +so that the glyphcodes in DejaVuASCIIToGlyphCode are guaranteed to
1.248 +work.
1.249 +
1.250 +@param aSeed Specifies a variant of the fontspec to create. Passing the
1.251 + same seed will cause the same TFontSpec to be returned.
1.252 +@return The generated fontspec.
1.253 + */
1.254 +static TFontSpec GenerateDejaVuFontSpec(TInt aSeed)
1.255 + {
1.256 + const TInt KFontHeightStep = 4;
1.257 + const TInt KFontInitialHeight = 8;
1.258 +
1.259 + const TInt KNumFontTypefaces = 3;
1.260 + const TInt KNumFontBitmapTypes = 2;
1.261 + const TInt KNumFontStyles = 4;
1.262 +
1.263 + TInt fontBitmapTypeVariant = aSeed % KNumFontBitmapTypes;
1.264 + TInt fontStyleVariant = (aSeed / KNumFontBitmapTypes) % KNumFontStyles;
1.265 + TInt fontTypefaceVariant = (aSeed / ( KNumFontStyles * KNumFontBitmapTypes)) % KNumFontTypefaces;
1.266 + TInt fontHeightVariant = aSeed / (KNumFontStyles * KNumFontTypefaces * KNumFontBitmapTypes);
1.267 +
1.268 + TFontSpec fontSpec;
1.269 + fontSpec.iHeight = KFontInitialHeight + (fontHeightVariant * KFontHeightStep);
1.270 + // Set the typeface name
1.271 + // Set the style.
1.272 + switch (fontStyleVariant)
1.273 + {
1.274 + case 1: // italic
1.275 + fontSpec.iFontStyle.SetPosture(EPostureItalic);
1.276 + fontSpec.iFontStyle.SetStrokeWeight(EStrokeWeightNormal);
1.277 + break;
1.278 + case 2: // bold
1.279 + fontSpec.iFontStyle.SetPosture(EPostureUpright);
1.280 + fontSpec.iFontStyle.SetStrokeWeight(EStrokeWeightBold);
1.281 + break;
1.282 + case 3: // bold italic
1.283 + fontSpec.iFontStyle.SetPosture(EPostureItalic);
1.284 + fontSpec.iFontStyle.SetStrokeWeight(EStrokeWeightBold);
1.285 + break;
1.286 + default: // normal
1.287 + fontSpec.iFontStyle.SetPosture(EPostureUpright);
1.288 + fontSpec.iFontStyle.SetStrokeWeight(EStrokeWeightNormal);
1.289 + break;
1.290 + }
1.291 + switch (fontTypefaceVariant)
1.292 + {
1.293 + case 1:
1.294 + fontSpec.iTypeface.SetName(_L("DejaVu Sans Mono"));
1.295 + break;
1.296 + case 2:
1.297 + fontSpec.iTypeface.SetName(_L("DejaVu Serif Condensed"));
1.298 + break;
1.299 + case 3:
1.300 + fontSpec.iTypeface.SetName(_L("DejaVu Sans Condensed"));
1.301 + break;
1.302 + }
1.303 + switch(fontBitmapTypeVariant)
1.304 + {
1.305 + case 1:
1.306 + fontSpec.iFontStyle.SetBitmapType(EMonochromeGlyphBitmap);
1.307 + break;
1.308 + default:
1.309 + fontSpec.iFontStyle.SetBitmapType(EAntiAliasedGlyphBitmap);
1.310 + break;
1.311 + }
1.312 +
1.313 + return fontSpec;
1.314 + }
1.315 +
1.316 +
1.317 +/**
1.318 + *
1.319 + EGL helper class to retrieve image data from an SgImage into a memory buffer.
1.320 + */
1.321 +CEGLHelper::CEGLHelper() :
1.322 + iDisplay(EGL_NO_DISPLAY),
1.323 + iContext(EGL_NO_CONTEXT),
1.324 + iSurface(EGL_NO_SURFACE)
1.325 + {
1.326 + }
1.327 +CEGLHelper::~CEGLHelper()
1.328 + {
1.329 + iMutex.Close();
1.330 + eglMakeCurrent(iDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
1.331 + eglDestroyContext(iDisplay, iContext);
1.332 + eglDestroySurface(iDisplay, iSurface);
1.333 + eglTerminate(iDisplay);
1.334 + eglReleaseThread();
1.335 + iSgDriver.Close();
1.336 + }
1.337 +
1.338 +/**
1.339 +Factory method to create CEGLHelper.
1.340 +@return A pointer to an instance of CEGLHelper.
1.341 + */
1.342 +CEGLHelper* CEGLHelper::NewL()
1.343 + {
1.344 + CEGLHelper* self = new CEGLHelper();
1.345 + CleanupStack::PushL(self);
1.346 + self->ConstructL();
1.347 + CleanupStack::Pop(1); // self
1.348 + return self;
1.349 + }
1.350 +
1.351 +/**
1.352 +Opens handle to the process-wide synchronisation semaphore,
1.353 +loads EGL and VG extension function pointers,
1.354 +sets up EGL resources so that EGLImages can be constructed.
1.355 + */
1.356 +void CEGLHelper::ConstructL()
1.357 + {
1.358 + _LIT(KEGLMutex, "TFbsGlyphDataEGLMutex");
1.359 + User::LeaveIfError(iMutex.CreateGlobal(KEGLMutex, EOwnerProcess));
1.360 + User::LeaveIfError(iSgDriver.Open());
1.361 +
1.362 + iDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
1.363 + if (iDisplay == EGL_NO_DISPLAY)
1.364 + {
1.365 + User::Leave(KErrNotSupported);
1.366 + }
1.367 + if (EGL_TRUE != eglInitialize(iDisplay, NULL, NULL))
1.368 + {
1.369 + User::Leave(KErrNotSupported);
1.370 + }
1.371 + eglBindAPI(EGL_OPENVG_API);
1.372 +
1.373 + // Load the necessary EGL extensions...
1.374 + eglCreateImageKHR = reinterpret_cast<PFNEGLCREATEIMAGEKHRPROC>(eglGetProcAddress("eglCreateImageKHR"));
1.375 + eglDestroyImageKHR = reinterpret_cast<PFNEGLDESTROYIMAGEKHRPROC>(eglGetProcAddress("eglDestroyImageKHR"));
1.376 + vgCreateImageTargetKHR = reinterpret_cast<TvgCreateEGLImageTargetKHRTypefPtr>(eglGetProcAddress("vgCreateEGLImageTargetKHR"));
1.377 + if (!eglCreateImageKHR || !eglDestroyImageKHR || !vgCreateImageTargetKHR)
1.378 + {
1.379 + User::Leave(KErrExtensionNotSupported);
1.380 + }
1.381 +
1.382 + // In order to create VGImages from EGLImages, a context must be current.
1.383 + // Therefore create an EGLContext and EGLSurface to make current, using
1.384 + // a dummy RSgImage.
1.385 +
1.386 + RSgImage dummySurface;
1.387 + TSgImageInfo dummySurfaceInfo(TSize(1, 1), ESgPixelFormatRGB_565, ESgUsageBitOpenVgSurface);
1.388 + User::LeaveIfError(dummySurface.Create(dummySurfaceInfo, NULL, 0));
1.389 + CleanupClosePushL(dummySurface);
1.390 +
1.391 + EGLint configAttribs[] =
1.392 + {
1.393 + EGL_MATCH_NATIVE_PIXMAP, (EGLint)&dummySurface,
1.394 + EGL_RENDERABLE_TYPE, EGL_OPENVG_BIT,
1.395 + EGL_NONE
1.396 + };
1.397 +
1.398 + EGLint configId = 0;
1.399 + EGLint numConfigs = 0;
1.400 + if (EGL_FALSE == eglChooseConfig(iDisplay, configAttribs, &configId, 1, &numConfigs) || numConfigs == 0)
1.401 + {
1.402 + User::Leave(KErrGeneral);
1.403 + }
1.404 + iContext = eglCreateContext(iDisplay, configId, EGL_NO_CONTEXT, NULL);
1.405 + if (iContext == EGL_NO_CONTEXT)
1.406 + {
1.407 + User::Leave(KErrGeneral);
1.408 + }
1.409 + iSurface = eglCreatePixmapSurface(iDisplay, configId, &dummySurface, NULL);
1.410 + if (iSurface == EGL_NO_SURFACE)
1.411 + {
1.412 + User::Leave(KErrGeneral);
1.413 + }
1.414 + CleanupStack::PopAndDestroy(1); // dummySurface
1.415 + }
1.416 +
1.417 +/**
1.418 +Retrieves the data from an A8 RSgImage into a buffer.
1.419 +To do this, the RSgImage is converted to an EGLImage, then to a VGImage,
1.420 +where the image memory is read into the given buffer.
1.421 +The function can be called from multiple threads and synchronisation
1.422 +with EGL is controlled via a mutex.
1.423 +
1.424 +@param aSgImage The RSgImage to convert.
1.425 +@param aRect A rectangular region of the RSgImage to convert.
1.426 +@param aBuf On success, contains the image data of the RSgImage.
1.427 +@return One of the system-wide error codes.
1.428 + */
1.429 +TInt CEGLHelper::GetSgImageData(const RSgImage& aSgImage, const TRect& aRect, TUint8*& aBuf)
1.430 + {
1.431 + const TSize bufferSize = aRect.Size();
1.432 + const TInt dataStride = bufferSize.iWidth;
1.433 +
1.434 + if (bufferSize == TSize(0,0))
1.435 + {
1.436 + return KErrNone;
1.437 + }
1.438 + iMutex.Wait();
1.439 +
1.440 + TInt err = KErrNone;
1.441 + EGLImageKHR eglImage;
1.442 + if (EGL_FALSE == eglBindAPI(EGL_OPENVG_API))
1.443 + {
1.444 + err = KErrGeneral;
1.445 + }
1.446 + else if (EGL_FALSE == eglMakeCurrent(iDisplay, iSurface, iSurface, iContext))
1.447 + {
1.448 + err = KErrGeneral;
1.449 + }
1.450 + else
1.451 + {
1.452 + // Create EGLImages from the RSgImage.
1.453 + EGLint imageAttribs[] =
1.454 + {
1.455 + EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
1.456 + EGL_NONE
1.457 + };
1.458 + eglImage = eglCreateImageKHR(iDisplay, EGL_NO_CONTEXT, EGL_NATIVE_PIXMAP_KHR, reinterpret_cast<EGLClientBuffer>(&aSgImage), imageAttribs);
1.459 + if (eglImage == EGL_NO_IMAGE_KHR)
1.460 + {
1.461 + err = KErrArgument;
1.462 + }
1.463 + }
1.464 + if (err == KErrNone)
1.465 + {
1.466 + // Create VGImages from the EGLImage.
1.467 + VGImage vgImage = vgCreateImageTargetKHR(eglImage);
1.468 + eglDestroyImageKHR(iDisplay, eglImage);
1.469 + if (vgImage == VG_INVALID_HANDLE)
1.470 + {
1.471 + err = KErrArgument;
1.472 + }
1.473 + else
1.474 + {
1.475 + // Get the image data in 8bpp format
1.476 + vgGetImageSubData(vgImage, aBuf, dataStride, VG_A_8, aRect.iTl.iX, aRect.iTl.iY, bufferSize.iWidth, bufferSize.iHeight);
1.477 + vgDestroyImage(vgImage);
1.478 + }
1.479 + }
1.480 + eglReleaseThread();
1.481 + iMutex.Signal();
1.482 + return err;
1.483 + }
1.484 +
1.485 +CTFbsGlyphData::CTFbsGlyphData(CTestStep* aStep):
1.486 + CTGraphicsBase(aStep)
1.487 + {
1.488 + }
1.489 +
1.490 +void CTFbsGlyphData::ConstructL()
1.491 + {
1.492 + User::LeaveIfError(Logger().ShareAuto());
1.493 + User::LeaveIfError(RFbsSession::Connect());
1.494 + iFbs = RFbsSession::GetSession();
1.495 + iTs = (CFbsTypefaceStore*)CFbsTypefaceStore::NewL(NULL);
1.496 + User::LeaveIfError(iTs->GetNearestFontToDesignHeightInPixels((CFont*&)iFont, TFontSpec(KTypefaceName, 15)));
1.497 + User::LeaveIfError(iTs->GetNearestFontToDesignHeightInPixels((CFont*&)iFont2, TFontSpec(KTypefaceName, 8)));
1.498 +
1.499 + CCharCodeConverter* converter = CCharCodeConverter::NewLC();
1.500 + converter->UseFontL(iFont);
1.501 + iGlyphCodesLatin = new(ELeave) TUint[KNumGlyphCodesLatin];
1.502 + for (TInt ii = 0; ii < KNumGlyphCodesLatin; ++ii)
1.503 + {
1.504 + TUint asciiCode = ii+0x20; // ASCII characters from 0020 to 007F
1.505 + iGlyphCodesLatin[ii] = converter->GlyphCodeL(asciiCode);
1.506 + }
1.507 + CleanupStack::PopAndDestroy(1); // converter
1.508 +
1.509 + User::LeaveIfError(iSgDriver.Open());
1.510 + iEGL = CEGLHelper::NewL();
1.511 +
1.512 + // Creating a CFbsBitmap will force the RFbsSession to allocate a scanline buffer
1.513 + // now rather than in the middle of a test, thus avoiding heap check failure.
1.514 + CFbsBitmap* dummyBitmap = new (ELeave) CFbsBitmap;
1.515 + CleanupStack::PushL(dummyBitmap);
1.516 + User::LeaveIfError(dummyBitmap->Create(TSize(512, 1), EGray256));
1.517 + CleanupStack::PopAndDestroy(dummyBitmap);
1.518 +
1.519 + INFO_PRINTF1(_L("FBSERV Glyph Data Testing"));
1.520 + }
1.521 +
1.522 +
1.523 +
1.524 +
1.525 +CTFbsGlyphData::~CTFbsGlyphData()
1.526 + {
1.527 + delete iEGL;
1.528 + iSgDriver.Close();
1.529 + if (iTs)
1.530 + {
1.531 + iTs->ReleaseFont(iFont);
1.532 + iTs->ReleaseFont(iFont2);
1.533 + }
1.534 + delete iTs;
1.535 + delete[] iGlyphCodesLatin;
1.536 + User::Free(iTempBuf1);
1.537 + User::Free(iTempBuf2);
1.538 + RFbsSession::Disconnect();
1.539 + }
1.540 +
1.541 +void CTFbsGlyphData::RunTestCaseL(TInt aCurTestCase)
1.542 + {
1.543 + ((CTFbsGlyphDataStep*)iStep)->SetTestStepID(KUnknownSYMTestCaseIDName);
1.544 +
1.545 + TRAPD(leave,
1.546 +
1.547 + switch(aCurTestCase)
1.548 + {
1.549 + case 1:
1.550 + ((CTFbsGlyphDataStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0624"));
1.551 + TestConsistencyWithGetCharacterData();
1.552 + break;
1.553 + case 2:
1.554 + ((CTFbsGlyphDataStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0625"));
1.555 + TestInvalidGlyphCode();
1.556 + break;
1.557 + case 3:
1.558 + ((CTFbsGlyphDataStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0626"));
1.559 + TestGlyphMetricsArrayParameters();
1.560 + break;
1.561 + case 4:
1.562 + ((CTFbsGlyphDataStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0627"));
1.563 + TestGlyphMetricsArrayReuse();
1.564 + break;
1.565 + case 5:
1.566 + ((CTFbsGlyphDataStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0628"));
1.567 + TestGlyphDataIteratorClose();
1.568 + break;
1.569 + case 6:
1.570 + ((CTFbsGlyphDataStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0629"));
1.571 + TestGlyphDataIteratorSequence();
1.572 + break;
1.573 + case 7:
1.574 + ((CTFbsGlyphDataStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0632"));
1.575 + TestGlyphDataIteratorMultipleUsesOnMultipleFonts();
1.576 + break;
1.577 + case 8:
1.578 + ((CTFbsGlyphDataStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0633"));
1.579 + TestGlyphDataIteratorImageValidity();
1.580 + break;
1.581 + case 9:
1.582 + ((CTFbsGlyphDataStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0634"));
1.583 + TestGlyphDataIteratorOpenInvalidCode();
1.584 + break;
1.585 + case 10:
1.586 + ((CTFbsGlyphDataStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0636"));
1.587 + TestGlyphDataIteratorOpenTwice();
1.588 + break;
1.589 + case 11:
1.590 + ((CTFbsGlyphDataStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0637"));
1.591 + TestGlyphDataIteratorOpenTwiceWithDifferentFonts();
1.592 + break;
1.593 + case 12:
1.594 + ((CTFbsGlyphDataStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0638"));
1.595 + TestGlyphDataIteratorOpenTooBigFont();
1.596 + break;
1.597 + case 13:
1.598 + ((CTFbsGlyphDataStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0640"));
1.599 + TestGlyphDataIteratorOpenWithWrongArgument();
1.600 + break;
1.601 + case 14:
1.602 + ((CTFbsGlyphDataStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0641"));
1.603 + TestGlyphDataIteratorImageMemoryLeak();
1.604 + break;
1.605 + case 15:
1.606 + ((CTFbsGlyphDataStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0662"));
1.607 + TestGlyphDataIteratorNoGraphicsMemory();
1.608 + break;
1.609 + case 16:
1.610 + ((CTFbsGlyphDataStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0659"));
1.611 + TestGlyphDataIteratorLargeFontStress();
1.612 + break;
1.613 + case 17:
1.614 + ((CTFbsGlyphDataStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0660"));
1.615 + TestGlyphDataIteratorManyFontsStressL();
1.616 + break;
1.617 + case 18:
1.618 + ((CTFbsGlyphDataStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0666"));
1.619 + TestGlyphDataIteratorNextIsAtomic();
1.620 + break;
1.621 + case 19:
1.622 + ((CTFbsGlyphDataStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0665"));
1.623 + TestGlyphDataIteratorSameGlyphCodes();
1.624 + break;
1.625 + case 20:
1.626 + ((CTFbsGlyphDataStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0668"));
1.627 + TestGlyphDataIteratorManyArraySizes();
1.628 + break;
1.629 + case 21:
1.630 + ((CTFbsGlyphDataStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0669"));
1.631 + TestBitmapFontSupport();
1.632 + break;
1.633 + case 22:
1.634 + ((CTFbsGlyphDataStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0671"));
1.635 + TestMultithreadShareSingleFont();
1.636 + break;
1.637 + case 23:
1.638 + ((CTFbsGlyphDataStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0672"));
1.639 + TestMultithreadStressAtlas();
1.640 + break;
1.641 + case 24:
1.642 + ((CTFbsGlyphDataStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0673"));
1.643 + TestGlyphMetricsArrayHeapOOML();
1.644 + break;
1.645 + case 25:
1.646 + ((CTFbsGlyphDataStep*)iStep)->SetTestStepID(_L("GRAPHICS-FBSERV-0674"));
1.647 + TestGlyphDataIteratorHeapOOML();
1.648 + break;
1.649 + default:
1.650 + ((CTFbsGlyphDataStep*)iStep)->SetTestStepID(KNotATestSYMTestCaseIDName);
1.651 + ((CTFbsGlyphDataStep*)iStep)->CloseTMSGraphicsStep();
1.652 + TestComplete();
1.653 + break;
1.654 + }
1.655 +
1.656 + ); // TRAPD
1.657 +
1.658 + if (leave != KErrNone)
1.659 + {
1.660 + ERR_PRINTF2(_L("Leave %d occurred during test"), leave);
1.661 + iStep->SetTestStepResult(EFail);
1.662 + }
1.663 +
1.664 + ((CTFbsGlyphDataStep*)iStep)->RecordTestResultL();
1.665 + }
1.666 +
1.667 +
1.668 +/**
1.669 +@SYMTestCaseID GRAPHICS-FBSERV-0624
1.670 +@SYMTestPriority High
1.671 +@SYMTestType UT
1.672 +@SYMTestStatus Implemented
1.673 +@SYMPREQ PREQ2678
1.674 +
1.675 +@SYMTestCaseDesc
1.676 + Shows that RFbsGlyphMetricsArray::Get() and CFont::GetCharacterData() all
1.677 + provide the same metrics for the same set of glyph codes when using a CFbsFont.
1.678 + Shows that RFbsGlyphDataIterator::Metrics() and CFont::GetCharacterData()
1.679 + provide the same metrics for the same set of glyph codes.
1.680 +
1.681 +@SYMTestActions
1.682 + i. Call RFbsGlyphMetricsArray::Get() for a set of glyph codes with 1 glyph code per call.
1.683 + ii. Call RFbsGlyphMetricsArray::Get() for a set of glyph codes all in 1 call.
1.684 + iii. Call RFbsGlyphDataIterator::Open() for a set of glyph codes.
1.685 + iv. Call CFont::GetCharacterData() for the same set of glyph codes.
1.686 + v. Compare the metrics for each glyph code from all calls.
1.687 +
1.688 +@SYMTestExpectedResults
1.689 + For each glyph code, metrics received from RFbsGlyphMetricsArray::Get() and
1.690 + CFont::GetCharacterData() and RFbsGlyphDataIterator are all the same.
1.691 +*/
1.692 +void CTFbsGlyphData::TestConsistencyWithGetCharacterData()
1.693 + {
1.694 + INFO_PRINTF1(_L("Test RFbsGlyphMetricsArray::Get() with GetCharacterData()"));
1.695 +
1.696 + __UHEAP_MARK;
1.697 +
1.698 + RFbsGlyphDataIterator iter;
1.699 + RFbsGlyphMetricsArray glyphMetricsArray;
1.700 + RFbsGlyphMetricsArray glyphMetricsArraySingle;
1.701 +
1.702 + TInt numMismatches = 0;
1.703 + TOpenFontCharMetrics charMetrics;
1.704 + TSize bitmapSize;
1.705 + const TUint8* bitmapData = NULL;
1.706 +
1.707 + // Retrieve list of metrics for all glyph codes in one call
1.708 + TInt err = glyphMetricsArray.Get(*iFont, iGlyphCodesLatin, KNumGlyphCodesLatin);
1.709 + TESTNOERROR(err);
1.710 + if (err == KErrNone)
1.711 + {
1.712 + TEST(KNumGlyphCodesLatin == glyphMetricsArray.Count());
1.713 +
1.714 + TInt index = 0;
1.715 + TInt iterErr = iter.Open(*iFont, iGlyphCodesLatin, KNumGlyphCodesLatin);
1.716 + TESTNOERROR(iterErr);
1.717 + for (; iterErr == KErrNone; iterErr = iter.Next(), index++)
1.718 + {
1.719 + iFont->GetCharacterData(iGlyphCodesLatin[index] | KGlyphCodeFlag, charMetrics, bitmapData, bitmapSize);
1.720 +
1.721 + // Retrieve the metrics for each glyph code, one at a time
1.722 + TESTNOERROR(err = glyphMetricsArraySingle.Get(*iFont, &iGlyphCodesLatin[index], 1));
1.723 + if (KErrNone == err)
1.724 + {
1.725 + // Compare GetCharacterData() metrics with single RFbsGlyphMetricsArray.
1.726 + TUint32 comparison1 = CompareMetrics(charMetrics, glyphMetricsArraySingle[0]);
1.727 + // Compare GetCharacterData() metrics with large RFbsGlyphMetricsArray.
1.728 + TUint32 comparison2 = CompareMetrics(charMetrics, glyphMetricsArray[index]);
1.729 + // Compare GetCharacterData() metrics with RFbsGlyphDataIterator.
1.730 + TUint32 comparison3 = CompareMetrics(charMetrics, iter.Metrics());
1.731 + if (comparison1 != 0 || comparison2 != 0 || comparison3 != 0)
1.732 + {
1.733 + ERR_PRINTF5(_L("Glyphcode %i : Metrics mismatch: %d/%d/%d"), iGlyphCodesLatin[index], comparison1, comparison2, comparison3);
1.734 + ++numMismatches;
1.735 + }
1.736 + }
1.737 + }
1.738 + iter.Close();
1.739 + glyphMetricsArray.Close();
1.740 + glyphMetricsArraySingle.Close();
1.741 + TESTE(iterErr == KErrNotFound, iterErr);
1.742 + TEST(numMismatches == 0);
1.743 + TEST(index == KNumGlyphCodesLatin);
1.744 + }
1.745 +
1.746 + __UHEAP_MARKEND;
1.747 + }
1.748 +
1.749 +/**
1.750 +@return A series of success/fail booleans as a bitmask. A return value of zero
1.751 + indicates all tests passed, a result of 1 indicates the first test case failed,
1.752 + a return of 3 indicates the first and second test failed, and so on.
1.753 +*/
1.754 +TUint32 CTFbsGlyphData::CompareMetrics(const TOpenFontCharMetrics& aMetrics1, const TOpenFontCharMetrics& aMetrics2)
1.755 + {
1.756 + TUint32 result = 0;
1.757 + result |= (aMetrics1.Width() == aMetrics2.Width()) ? 0 : (1 << 0);
1.758 + result |= (aMetrics1.Height() == aMetrics2.Height()) ? 0 : (1 << 1);
1.759 + result |= (aMetrics1.HorizBearingX() == aMetrics2.HorizBearingX()) ? 0 : (1 << 2);
1.760 + result |= (aMetrics1.HorizBearingY() == aMetrics2.HorizBearingY()) ? 0 : (1 << 3);
1.761 + result |= (aMetrics1.HorizAdvance() == aMetrics2.HorizAdvance()) ? 0 : (1 << 4);
1.762 + result |= (aMetrics1.VertBearingX() == aMetrics2.VertBearingX()) ? 0 : (1 << 5);
1.763 + result |= (aMetrics1.VertBearingY() == aMetrics2.VertBearingY()) ? 0 : (1 << 6);
1.764 + result |= (aMetrics1.VertAdvance() == aMetrics2.VertAdvance()) ? 0 : (1 << 7);
1.765 + TRect rect1;
1.766 + aMetrics1.GetHorizBounds(rect1);
1.767 + TRect rect2;
1.768 + aMetrics2.GetHorizBounds(rect2);
1.769 + result |= (rect1 == rect2) ? 0 : (1 << 8);
1.770 + aMetrics1.GetVertBounds(rect1);
1.771 + aMetrics2.GetVertBounds(rect2);
1.772 + result |= (rect1 == rect2) ? 0 : (1 << 9);
1.773 + return result;
1.774 + }
1.775 +
1.776 +
1.777 +/**
1.778 +@SYMTestCaseID GRAPHICS-FBSERV-0625
1.779 +@SYMTestPriority High
1.780 +@SYMTestType UT
1.781 +@SYMTestStatus Implemented
1.782 +@SYMPREQ PREQ2678
1.783 +
1.784 +@SYMTestCaseDesc
1.785 + Shows that RFbsGlyphMetricsArray::Get(), and CFont::GetCharacterData() show the same
1.786 + behaviour when asked for metrics for an invalid glyph code when using a CFbsFont.
1.787 + An invalid glyph code is one for which there is no character equivalent, such as
1.788 + 0.
1.789 +
1.790 +@SYMTestActions
1.791 + i. Call CFont::GetCharacterData() for an invalid glyph code.
1.792 + ii. Call RFbsGlyphMetricsArray::Get() for the same invalid glyph code, and either
1.793 + compare the metrics if i. was successful, or check an error code was returned
1.794 +
1.795 +@SYMTestExpectedResults
1.796 + If GetCharacterData() is successful, the metrics received from
1.797 + RFbsGlyphMetricsArray::Get() and CFont::GetCharacterData() are the same, otherwise
1.798 + RFbsGlyphMetricsArray::Get() should return an error code.
1.799 +*/
1.800 +
1.801 +void CTFbsGlyphData::TestInvalidGlyphCode()
1.802 + {
1.803 + INFO_PRINTF1(_L("Test behaviour of RFbsGlyphMetricsArray::Get() with invalid glyph code is consistent with GetCharacterData"));
1.804 +
1.805 + __UHEAP_MARK;
1.806 + TInt arrayErr = KErrNone;
1.807 + RFbsGlyphMetricsArray glyphMetricsArray;
1.808 + TOpenFontCharMetrics charMetrics;
1.809 + TSize bitmapSize;
1.810 + const TUint8* bitmapData = NULL;
1.811 +
1.812 + CFont::TCharacterDataAvailability availability = iFont->GetCharacterData(KDejaVuInvalidGlyphCode | KGlyphCodeFlag, charMetrics, bitmapData, bitmapSize);
1.813 + if (availability == CFont::ENoCharacterData)
1.814 + {
1.815 + // Some rasterizers fail to return any data for KDejaVuInvalidGlyphCode, therefore
1.816 + // rather than compare metrics, make sure RFbsGlyphDataIterator returns an error code.
1.817 + WARN_PRINTF1(_L("Rasterizer failed to return data for invalid glyph code; not comparing glyph metrics"));
1.818 + arrayErr = glyphMetricsArray.Get(*iFont, &KDejaVuInvalidGlyphCode, 1);
1.819 + TESTE(arrayErr != KErrNone, arrayErr);
1.820 + }
1.821 + else
1.822 + {
1.823 + TESTNOERROR(arrayErr = glyphMetricsArray.Get(*iFont, &KDejaVuInvalidGlyphCode, 1));
1.824 + if (KErrNone == arrayErr)
1.825 + {
1.826 + iFont->GetCharacterData(KDejaVuInvalidGlyphCode | KGlyphCodeFlag, charMetrics, bitmapData, bitmapSize);
1.827 + TUint comparisonResult = CompareMetrics(charMetrics, glyphMetricsArray[0]);
1.828 + TESTNOERROR( comparisonResult );
1.829 + }
1.830 + }
1.831 + glyphMetricsArray.Close();
1.832 +
1.833 + __UHEAP_MARKEND;
1.834 + }
1.835 +
1.836 +/**
1.837 +@SYMTestCaseID GRAPHICS-FBSERV-0626
1.838 +@SYMTestPriority High
1.839 +@SYMTestType UT
1.840 +@SYMTestStatus Implemented
1.841 +@SYMPREQ PREQ2678
1.842 +
1.843 +@SYMTestCaseDesc
1.844 + Shows that RFbsGlyphMetricsArray::Get() returns with the correct error code when passed
1.845 + various combinations of parameters, and preserves the state of the array.
1.846 +
1.847 +@SYMTestActions
1.848 + Populate the array with a single metrics entry.
1.849 + Call RFbsGlyphMetricsArray::Get with the following parameter combinations:
1.850 + 1. A negative count
1.851 + 2. A positive count and null glyph code array pointer
1.852 + 3. A zero count and non-null glyph code array pointer
1.853 + 4. A zero count and null glyph code array pointer
1.854 +
1.855 +@SYMTestExpectedResults
1.856 + The following return codes are expected for each call:
1.857 + 1. KErrArgument
1.858 + 2. KErrArgument
1.859 + 3. KErrArgument
1.860 + 4. KErrArgument
1.861 + For each case the glyph metrics array remains unchanged.
1.862 +*/
1.863 +void CTFbsGlyphData::TestGlyphMetricsArrayParameters()
1.864 + {
1.865 + INFO_PRINTF1(_L("Test the return values of GetGlyphMetrics with different parameters"));
1.866 + __UHEAP_MARK;
1.867 + TInt arrayErr = KErrNone;
1.868 + TOpenFontCharMetrics dummyMetrics;
1.869 +
1.870 + RFbsGlyphMetricsArray glyphMetricsArray;
1.871 + arrayErr = glyphMetricsArray.Get(*iFont, iGlyphCodesLatin, 1);
1.872 + TESTNOERROR(arrayErr);
1.873 + TEST(1 == glyphMetricsArray.Count());
1.874 +
1.875 + // 1. Negative Count
1.876 + arrayErr = glyphMetricsArray.Get(*iFont, iGlyphCodesLatin, -1);
1.877 + TESTE(KErrArgument == arrayErr, arrayErr);
1.878 + TEST(1 == glyphMetricsArray.Count());
1.879 +
1.880 + // 2. Positive Count and NULL Array Pointer
1.881 + arrayErr = glyphMetricsArray.Get(*iFont, NULL, 1);
1.882 + TESTE(KErrArgument == arrayErr, arrayErr);
1.883 + TEST(1 == glyphMetricsArray.Count());
1.884 +
1.885 + // 3. Zero Count & Valid Array Pointer
1.886 + arrayErr = glyphMetricsArray.Get(*iFont, iGlyphCodesLatin, 0);
1.887 + TESTE(KErrArgument == arrayErr, arrayErr);
1.888 +
1.889 + // 4. Zero Count & NULL Array Pointer
1.890 + arrayErr = glyphMetricsArray.Get(*iFont, NULL, 0);
1.891 + TESTE(KErrArgument == arrayErr, arrayErr);
1.892 +
1.893 + glyphMetricsArray.Close();
1.894 + __UHEAP_MARKEND;
1.895 + }
1.896 +
1.897 +/**
1.898 +@SYMTestCaseID GRAPHICS-FBSERV-0627
1.899 +@SYMTestPriority High
1.900 +@SYMTestType UT
1.901 +@SYMTestStatus Implemented
1.902 +@SYMPREQ PREQ2678
1.903 +
1.904 +@SYMTestCaseDesc
1.905 + Shows that reusing an RFbsGlyphMetricsArray works correctly.
1.906 + In particular when the array is reused and filled with fewer entries
1.907 + and when the array is reused and filled with more entries than previously.
1.908 + It also shows that when re-using an array that has been populated, memory
1.909 + is not de-allocated if the new array of glyphs is smaller.
1.910 +
1.911 +@SYMTestActions
1.912 + i. Call RFbsGlyphMetricsArray::Get() for a set of 10 glyph codes.
1.913 + ii. Check that the RFbsGlyphMetricsArray has 10 entries.
1.914 + iii. Find the size of the heap-cell allocated to the array.
1.915 + iii. Call RFbsGlyphMetricsArray::Get() for a set of 5 glyph codes.
1.916 + iv. Check that the RFbsGlyphMetricsArray has 5 entries.
1.917 + v. Call RFbsGlyphMetricsArray::Get() for a set of 20 glyph codes.
1.918 + vi. Check that the RFbsGlyphMetricsArray has 20 entries.
1.919 + vii. Call RFbsGlyphMetricsArray::Get() for a set of 0 glyph codes.
1.920 + viii. Check that the RFbsGlyphMetricsArray has 0 entries.
1.921 + ix. Call RFbsGlyphMetricsArray::Get() for 1 glyph code.
1.922 + x. Check that the RFbsGlyphMetricsArray has 1 entries.
1.923 + xi. Close the RFbsGlyphMetricsArray.
1.924 + xii. Check that the RFbsGlyphMetricsArray has 0 entries.
1.925 + During the test check that the size of the heap cell allocated to the array
1.926 + does not shrink.
1.927 +
1.928 +@SYMTestExpectedResults
1.929 + After each call to RFbsGlyphMetricsArray::Get(), the array has the expected number of entries.
1.930 +*/
1.931 +void CTFbsGlyphData::TestGlyphMetricsArrayReuse()
1.932 + {
1.933 + INFO_PRINTF1(_L("Test reuse of array with RFbsGlyphMetricsArray"));
1.934 + __UHEAP_MARK;
1.935 +
1.936 + RFbsGlyphMetricsArray glyphMetricsArray;
1.937 +
1.938 + // Retrieve list of metrics for 10 glyph codes
1.939 + TESTNOERROR(glyphMetricsArray.Get(*iFont, iGlyphCodesLatin, 10));
1.940 + TEST(10 == glyphMetricsArray.Count());
1.941 +
1.942 + // Find the size of the heap cell allocated for the array.
1.943 + TInt arrayHeapCellSize = User::Heap().AllocLen(&glyphMetricsArray[0]);
1.944 +
1.945 + // Retrieve list of metrics for 5 glyph codes.
1.946 + // To ensure that different metrics are returned, use different glyph codes
1.947 + TESTNOERROR(glyphMetricsArray.Get(*iFont, &iGlyphCodesLatin[10], 5));
1.948 + TEST(5 == glyphMetricsArray.Count());
1.949 + // Check that memory has not been de-allocated for a smaller array.
1.950 + TEST(User::Heap().AllocLen(&glyphMetricsArray[0]) == arrayHeapCellSize);
1.951 +
1.952 + // Retrieve list of metrics for 20 glyph codes.
1.953 + // To ensure that different metrics are returned, use different glyph codes
1.954 + TESTNOERROR(glyphMetricsArray.Get(*iFont, &iGlyphCodesLatin[15], 20));
1.955 + TEST(20 == glyphMetricsArray.Count());
1.956 + arrayHeapCellSize = User::Heap().AllocLen(&glyphMetricsArray[0]);
1.957 +
1.958 + // Retrieve list of metrics for 0 glyph codes.
1.959 + TEST(KErrArgument == glyphMetricsArray.Get(*iFont, &iGlyphCodesLatin[35], 0));
1.960 + // We can't check whether memory has been de-allocated as glyphMetricsArray[0]
1.961 + // is null, therefore dereferencing it causes a panic.
1.962 +
1.963 + // Retrieve list of metrics for 1 glyph code.
1.964 + // To ensure that different metrics are returned, use different glyph code
1.965 + TESTNOERROR(glyphMetricsArray.Get(*iFont, &iGlyphCodesLatin[35], 1));
1.966 + TEST(1 == glyphMetricsArray.Count());
1.967 + TEST(User::Heap().AllocLen(&glyphMetricsArray[0]) == arrayHeapCellSize);
1.968 +
1.969 + // Test that after closing a non-empty array, the array has 0 size.
1.970 + glyphMetricsArray.Close();
1.971 + TEST(0 == glyphMetricsArray.Count());
1.972 +
1.973 + __UHEAP_MARKEND;
1.974 + }
1.975 +
1.976 +/**
1.977 +@SYMTestCaseID GRAPHICS-FBSERV-0628
1.978 +@SYMTestPriority High
1.979 +@SYMTestType UT
1.980 +@SYMTestStatus Implemented
1.981 +@SYMPREQ PREQ2678
1.982 +
1.983 +@SYMTestCaseDesc
1.984 + Validates the behaviour of RFbsGlyphDataIterator::Close() in the following use cases:
1.985 + 1. When called on an iterator instance which has not been opened, has no effect.
1.986 + 2. When called on an open iterator closes the iterator
1.987 +
1.988 +@SYMTestActions
1.989 + Use case 1:
1.990 + i. Create an RFbsGlyphDataIterator instance but do not open.
1.991 + ii. Call RFbsGlyphDataIterator::Close().
1.992 +
1.993 + Use case 2:
1.994 + i. Create an RFbsGlyphDataIterator instance and call RFbsGlyphDataIterator::Open().
1.995 + ii. Call RFbsGlyphDataIterator::Next() to prove the iterator is open.
1.996 + iii. Call RFbsGlyphDataIterator::Close().
1.997 + iv. Check that RFbsGlyphDataIterator::IsOpen() returns false.
1.998 +
1.999 +@SYMTestExpectedResults
1.1000 + Each call to RFbsGlyphDataIterator::IsOpen() returns the expected value.
1.1001 +*/
1.1002 +void CTFbsGlyphData::TestGlyphDataIteratorClose()
1.1003 + {
1.1004 + INFO_PRINTF1(_L("Test closing an RFbsGlyphDataIterator"));
1.1005 + __UHEAP_MARK;
1.1006 +
1.1007 + // Use case 1
1.1008 + RFbsGlyphDataIterator iter1;
1.1009 + iter1.Close();
1.1010 +
1.1011 + // Use case 2
1.1012 + RFbsGlyphDataIterator iter2;
1.1013 + TESTNOERROR(iter2.Open(*iFont, iGlyphCodesLatin, 1));
1.1014 + TInt iterErr = iter2.Next();
1.1015 + TESTE(KErrNotFound == iterErr, iterErr);
1.1016 + iter2.Close();
1.1017 +
1.1018 + __UHEAP_MARKEND;
1.1019 + }
1.1020 +
1.1021 +/**
1.1022 +@SYMTestCaseID GRAPHICS-FBSERV-0629
1.1023 +@SYMTestPriority High
1.1024 +@SYMTestType UT
1.1025 +@SYMTestStatus Implemented
1.1026 +@SYMPREQ PREQ2678
1.1027 +
1.1028 +@SYMTestCaseDesc
1.1029 + Show that the sequence of iterations when calling RFbsGlyphDataIterator::Next()
1.1030 + matches the order of the array of glyph codes.
1.1031 +
1.1032 +@SYMTestActions
1.1033 + i. Create an RFbsGlyphDataIterator instance and call RFbsGlyphDataIterator::Open()
1.1034 + with an array of different glyph codes.
1.1035 + ii. Iterate through all the glyph data.
1.1036 + For each iteration check that the glyph code returned from
1.1037 + RFbsGlyphDataIterator::GlyphCode() matches the corresponding glyph code
1.1038 + passed into Open().
1.1039 +
1.1040 +@SYMTestExpectedResults
1.1041 + Each comparison of glyph code should match.
1.1042 +*/
1.1043 +void CTFbsGlyphData::TestGlyphDataIteratorSequence()
1.1044 + {
1.1045 + INFO_PRINTF1(_L("Test the iterator sequence of RFbsGlyphDataIterator"));
1.1046 + __UHEAP_MARK;
1.1047 +
1.1048 + TBool matches = ETrue;
1.1049 + TInt index = 0;
1.1050 +
1.1051 + RFbsGlyphDataIterator iter;
1.1052 + TInt iterErr = iter.Open(*iFont, iGlyphCodesLatin, KNumGlyphCodesLatin);
1.1053 + TESTNOERROR(iterErr);
1.1054 + for (; index < KNumGlyphCodesLatin && matches && (iterErr == KErrNone); iterErr = iter.Next(), index++)
1.1055 + {
1.1056 + if (iter.GlyphCode() != iGlyphCodesLatin[index])
1.1057 + {
1.1058 + ERR_PRINTF4(_L("Failed at iteration %d: wanted %d, got %d"), index, iGlyphCodesLatin[index], iter.GlyphCode());
1.1059 + matches = EFalse;
1.1060 + }
1.1061 + }
1.1062 + iter.Close();
1.1063 + TESTE(iterErr == KErrNotFound, iterErr);
1.1064 + TEST(matches);
1.1065 + TEST(index == KNumGlyphCodesLatin);
1.1066 + iter.Close();
1.1067 +
1.1068 + __UHEAP_MARKEND;
1.1069 + }
1.1070 +
1.1071 +/**
1.1072 +@SYMTestCaseID GRAPHICS-FBSERV-0632
1.1073 +@SYMTestPriority High
1.1074 +@SYMTestType UT
1.1075 +@SYMTestStatus Implemented
1.1076 +@SYMPREQ PREQ2678
1.1077 +
1.1078 +@SYMTestCaseDesc
1.1079 + Ensure it is possible to reuse a closed iterator on another CFbsFont.
1.1080 +
1.1081 +@SYMTestActions
1.1082 + i. Open an RFbsGlyphDataIterator with sample data.
1.1083 + ii. Iterate through until the end of the iterator has been reached by calling
1.1084 + Next() on the final element.
1.1085 + iii. Re-open the same RFbsGlyphDataIterator with sample data on a different CFbsFont.
1.1086 + iv. Iterate through a second time until the end has been reached by calling Next()
1.1087 + on the final element.
1.1088 + v. Close the iterator.
1.1089 + vi. During both iterations the bitmap data returned and metrics are compared with
1.1090 + the equivalent from GetCharacterData().
1.1091 +
1.1092 +@SYMTestExpectedResults
1.1093 + The iterator should be opened successfully for both fonts and the data returned
1.1094 + should match the data from GetCharacterData().
1.1095 +*/
1.1096 +void CTFbsGlyphData::TestGlyphDataIteratorMultipleUsesOnMultipleFonts()
1.1097 + {
1.1098 + INFO_PRINTF1(_L("Reuse a closed iterator on a second CFbsFont"));
1.1099 + __UHEAP_MARK;
1.1100 +
1.1101 + const TUint8* bitmapData;
1.1102 + TSize bitmapSize;
1.1103 + TOpenFontCharMetrics charMetrics;
1.1104 + RFbsGlyphDataIterator iter;
1.1105 +
1.1106 + // Array of fonts to iterate through.
1.1107 + CFbsFont* font[2] = {iFont, iFont2};
1.1108 +
1.1109 + for (TInt fontId = 0; fontId < 2; fontId++)
1.1110 + {
1.1111 + // On the first iteration, open and use a font until all glyphs have been iterated through.
1.1112 + // On second iteration, use the same iterator on a different font and repeat.
1.1113 + CFbsFont* currentFont = font[fontId];
1.1114 +
1.1115 + //Open the iterator on the first font and compare the returned bitmaps against GetCharacterData
1.1116 + TInt iterErr = iter.Open(*currentFont, iGlyphCodesLatin, KNumGlyphCodesLatin);
1.1117 + TESTNOERROR(iterErr);
1.1118 + TFontSpec fontSpec = currentFont->FontSpecInTwips();
1.1119 +
1.1120 + TInt index = 0;
1.1121 + for (; (iterErr == KErrNone) && (index < KNumGlyphCodesLatin); iterErr = iter.Next(), ++index)
1.1122 + {
1.1123 + currentFont->GetCharacterData(iGlyphCodesLatin[index] | KGlyphCodeFlag, charMetrics, bitmapData, bitmapSize);
1.1124 +
1.1125 + TESTNOERROR(CompareMetrics(charMetrics, iter.Metrics()));
1.1126 + if (bitmapSize == TSize(0, 0))
1.1127 + {
1.1128 + TEST(bitmapSize == iter.Rect().Size());
1.1129 + }
1.1130 + else
1.1131 + {
1.1132 + // Compare images.
1.1133 + TBool match = EFalse;
1.1134 + RSgImage characterDataImage;
1.1135 + TInt err = CreateSgImageFromCharacterData(bitmapData, bitmapSize, fontSpec.iFontStyle.BitmapType(), characterDataImage);
1.1136 + if (err == KErrNone)
1.1137 + {
1.1138 + err = CompareSgImages(iEGL, iter.Image(), iter.Rect(), characterDataImage, TRect(bitmapSize), match);
1.1139 + }
1.1140 + characterDataImage.Close();
1.1141 + if (err != KErrNone)
1.1142 + {
1.1143 + TESTNOERROR(err);
1.1144 + break;
1.1145 + }
1.1146 + TEST(match);
1.1147 + }
1.1148 + }
1.1149 + iter.Close();
1.1150 + TESTE(iterErr == KErrNotFound, iterErr);
1.1151 + TEST(index == KNumGlyphCodesLatin);
1.1152 + }
1.1153 +
1.1154 + __UHEAP_MARKEND;
1.1155 + }
1.1156 +
1.1157 +/**
1.1158 +@SYMTestCaseID GRAPHICS-FBSERV-0633
1.1159 +@SYMTestPriority High
1.1160 +@SYMTestType UT
1.1161 +@SYMTestStatus Implemented
1.1162 +@SYMPREQ PREQ2678
1.1163 +
1.1164 +@SYMTestCaseDesc
1.1165 + Check that for various Latin fonts, the images of the glyphs stored on the
1.1166 + RSgImage matches those provided by GetCharacterData().
1.1167 +
1.1168 +@SYMTestActions
1.1169 + Create a selection of fonts, using various typefaces, sizes and bitmap types.
1.1170 + For each font:
1.1171 + i. Open the RFbsGlyphDataIterator and iterate each glyph.
1.1172 + ii. For each glyph, call GetCharacterData() with the expected glyph code.
1.1173 + iii. Convert the character data to an RSgImage.
1.1174 + iv. Perform a comparison between the character RSgImage and the iterator
1.1175 + image.
1.1176 + v. After all iterations, close the iterator and check all expected glyphs
1.1177 + were iterated through.
1.1178 +
1.1179 +@SYMTestExpectedResults
1.1180 + All glyph images should match.
1.1181 +*/
1.1182 +void CTFbsGlyphData::TestGlyphDataIteratorImageValidity()
1.1183 + {
1.1184 + INFO_PRINTF1(_L("Test the glyph images of the iterator match GetCharacterData()"));
1.1185 + __UHEAP_MARK;
1.1186 +
1.1187 + const TInt KNumFonts = 20;
1.1188 +
1.1189 + // Create a new typeface store for this test so that heap checking will not
1.1190 + // be affected by cached CFbsFonts.
1.1191 + CFbsTypefaceStore* typefaceStore = NULL;
1.1192 + TRAPD(err, typefaceStore = CFbsTypefaceStore::NewL(NULL));
1.1193 + if (err != KErrNone)
1.1194 + {
1.1195 + ERR_PRINTF1(_L("Failed to construct typeface store. Test aborted."));
1.1196 + __UHEAP_RESET;
1.1197 + iStep->SetTestStepResult(EFail);
1.1198 + return;
1.1199 + }
1.1200 +
1.1201 + for (TInt font = 0; font < KNumFonts; ++font)
1.1202 + {
1.1203 + // Use either a pre-created bitmap-font TFontSpec, or generate a Deja-vu one.
1.1204 + TFontSpec fontSpec = GenerateDejaVuFontSpec(font);
1.1205 + CFbsFont* latinFont = NULL;
1.1206 + TESTNOERROR(typefaceStore->GetNearestFontToDesignHeightInPixels((CFont*&)latinFont, fontSpec));
1.1207 +
1.1208 + fontSpec = latinFont->FontSpecInTwips();
1.1209 + InfoPrintFontSpec(*latinFont);
1.1210 +
1.1211 + RFbsGlyphDataIterator iter;
1.1212 + TInt iterErr = iter.Open(*latinFont, iGlyphCodesLatin, KNumGlyphCodesLatin);
1.1213 + TESTNOERROR(iterErr);
1.1214 +
1.1215 + err = KErrNone;
1.1216 + TInt index = 0;
1.1217 + TInt numMismatches = 0;
1.1218 + // For each iteration, get the character data of the expected glyph.
1.1219 + // Create RSgImage from character data, and compare iter image with constructed image.
1.1220 + for (; (iterErr == KErrNone) && (err == KErrNone) && (index < KNumGlyphCodesLatin); (iterErr = iter.Next()), ++index)
1.1221 + {
1.1222 + TBool glyphMatches = ETrue;
1.1223 + const RSgImage& iteratorImage = iter.Image();
1.1224 +
1.1225 + const TUint8* bitmapData = NULL;
1.1226 + TSize bitmapSize;
1.1227 + TOpenFontCharMetrics metrics;
1.1228 + TInt characterDataAvailability = latinFont->GetCharacterData(iGlyphCodesLatin[index] | KGlyphCodeFlag, metrics, bitmapData, bitmapSize);
1.1229 + if (bitmapSize == TSize(0, 0))
1.1230 + {
1.1231 + glyphMatches = (bitmapSize == iter.Rect().Size());
1.1232 + }
1.1233 + else
1.1234 + {
1.1235 + RSgImage characterDataImage;
1.1236 + TESTNOERROR(CreateSgImageFromCharacterData(bitmapData, bitmapSize, fontSpec.iFontStyle.BitmapType(), characterDataImage));
1.1237 + err = CompareSgImages(iEGL, iteratorImage, iter.Rect(), characterDataImage, TRect(bitmapSize), glyphMatches);
1.1238 + characterDataImage.Close();
1.1239 + }
1.1240 + if (err == KErrNone && !glyphMatches)
1.1241 + {
1.1242 + ERR_PRINTF2(_L("Glyphcode %i : Image mismatch"), iGlyphCodesLatin[index]);
1.1243 + ++numMismatches;
1.1244 + }
1.1245 + }
1.1246 + iter.Close();
1.1247 + TESTNOERROR(err);
1.1248 + TESTE(iterErr == KErrNotFound, iterErr);
1.1249 + TEST(index == KNumGlyphCodesLatin);
1.1250 + TEST(numMismatches == 0);
1.1251 + typefaceStore->ReleaseFont(latinFont);
1.1252 + }
1.1253 + delete typefaceStore;
1.1254 + __UHEAP_MARKEND;
1.1255 + }
1.1256 +
1.1257 +/**
1.1258 +@SYMTestCaseID GRAPHICS-FBSERV-0634
1.1259 +@SYMTestPriority High
1.1260 +@SYMTestType UT
1.1261 +@SYMTestStatus Implemented
1.1262 +@SYMPREQ PREQ2678
1.1263 +
1.1264 +@SYMTestCaseDesc
1.1265 + To ensure that if the glyph image iterator has a current invalid
1.1266 + character code, the SgImage returned by the iterator will match
1.1267 + to the image obtained from the GetCharacterData() function
1.1268 +@SYMTestActions
1.1269 + i. Retrieve bitmap data and metrics by using GetCharacterData().
1.1270 + ii. Open a glyph data iterator passing an invalid character code.
1.1271 + iii. If i. was unsuccessful, check that opening the iterator returned
1.1272 + an error code and skip to ix.
1.1273 + iv. Create SgImage from bitmap data.
1.1274 + v. Get SgImage from the glyph data iterator.
1.1275 + vi. Compare SgImages obtained on iv and v steps.
1.1276 + vii. Get font metrics from the glyph data iterator.
1.1277 + viii. Compare metrics obtained on i and vii steps.
1.1278 + vii. Close the iterator.
1.1279 +
1.1280 +@SYMTestExpectedResults
1.1281 + If the request to get the character data failed, the return value of
1.1282 + RFbsGlyphDataIterator::Open() must not be KErrNone.
1.1283 + Otherwise, images obtained from the iterator and GetCharacterData() should
1.1284 + match.
1.1285 +*/
1.1286 +void CTFbsGlyphData::TestGlyphDataIteratorOpenInvalidCode()
1.1287 + {
1.1288 + INFO_PRINTF1(_L("Ensure that the image returned by the iterator will \
1.1289 +match to the image obtained from GetCharacterData() if character code is invalid"));
1.1290 + __UHEAP_MARK;
1.1291 +
1.1292 + const TUint8* bitmapData = NULL;
1.1293 + TSize bitmapSize;
1.1294 + TOpenFontCharMetrics metrics;
1.1295 + const TFontSpec fontSpec = iFont->FontSpecInTwips();
1.1296 + CFont::TCharacterDataAvailability availability = iFont->GetCharacterData(KDejaVuInvalidGlyphCode | KGlyphCodeFlag, metrics, bitmapData, bitmapSize);
1.1297 +
1.1298 + RFbsGlyphDataIterator iter;
1.1299 + TInt err = iter.Open(*iFont, &KDejaVuInvalidGlyphCode, 1);
1.1300 + if (availability == CFont::ENoCharacterData)
1.1301 + {
1.1302 + // Some rasterizers fail to return any data for KDejaVuInvalidGlyphCode, therefore
1.1303 + // rather than compare image contents, make sure RFbsGlyphDataIterator returns an error code.
1.1304 + WARN_PRINTF1(_L("Rasterizer failed to return data for invalid glyph code; not comparing image contents"));
1.1305 + TESTE(err != KErrNone, err);
1.1306 + }
1.1307 + else
1.1308 + {
1.1309 + TESTNOERROR(err);
1.1310 + if (err == KErrNone)
1.1311 + {
1.1312 + TBool glyphMatches = EFalse;
1.1313 + if (bitmapSize == TSize(0, 0))
1.1314 + {
1.1315 + glyphMatches = (bitmapSize == iter.Rect().Size());
1.1316 + }
1.1317 + else
1.1318 + {
1.1319 + RSgImage characterDataImage;
1.1320 + TESTNOERROR(CreateSgImageFromCharacterData(bitmapData, bitmapSize, fontSpec.iFontStyle.BitmapType(), characterDataImage));
1.1321 + TESTNOERROR(CompareSgImages(iEGL, iter.Image(), iter.Rect(), characterDataImage, TRect(bitmapSize), glyphMatches));
1.1322 + characterDataImage.Close();
1.1323 + }
1.1324 + TESTNOERROR(CompareMetrics(metrics, iter.Metrics()));
1.1325 + TEST(glyphMatches);
1.1326 + }
1.1327 + }
1.1328 + iter.Close();
1.1329 +
1.1330 + __UHEAP_MARKEND;
1.1331 + }
1.1332 +
1.1333 +
1.1334 +/**
1.1335 +@SYMTestCaseID GRAPHICS-FBSERV-0636
1.1336 +@SYMTestPriority High
1.1337 +@SYMTestType UT
1.1338 +@SYMTestStatus Implemented
1.1339 +@SYMPREQ PREQ2678
1.1340 +
1.1341 +@SYMTestCaseDesc
1.1342 + To ensure that opening the glyph data iterator which has already been opened with the same font
1.1343 + has no effect on the state of the iterator.
1.1344 +@SYMTestActions
1.1345 + i. Open glyph data iterator on 2 glyph codes.
1.1346 + ii. Try to open the glyph data iterator again on the same font.
1.1347 + iii. Call RFbsGlyphDataIterator::Next() on the iterator and check error code, making the last
1.1348 + glyph code the current iteration.
1.1349 + iv. Call RFbsGlyphDataIterator::Next() again.
1.1350 +@SYMTestExpectedResults
1.1351 + The second attempt to open the glyph data iterator will result an error with code KErrInUse.
1.1352 + The last two calls to RFbsGlyphDataIterator::Next() should return KErrNone and KErrNotFound
1.1353 + respectively, showing the iterator was not modified when the call to Open() failed.
1.1354 +*/
1.1355 +void CTFbsGlyphData::TestGlyphDataIteratorOpenTwice()
1.1356 + {
1.1357 + INFO_PRINTF1(_L("Ensure that opening the glyph data iterator which has already been opened with the same font has no effect"));
1.1358 + __UHEAP_MARK;
1.1359 +
1.1360 + RFbsGlyphDataIterator iter;
1.1361 + TInt iterErr = iter.Open(*iFont, iGlyphCodesLatin, 2);
1.1362 + TESTNOERROR(iterErr);
1.1363 +
1.1364 + iterErr = iter.Open(*iFont, iGlyphCodesLatin, KNumGlyphCodesLatin);
1.1365 + TESTE(iterErr == KErrInUse, iterErr);
1.1366 + iterErr = iter.Next();
1.1367 + TESTNOERROR(iterErr);
1.1368 + iterErr = iter.Next();
1.1369 + TESTE(iterErr == KErrNotFound, iterErr);
1.1370 + iter.Close();
1.1371 +
1.1372 + __UHEAP_MARKEND;
1.1373 + }
1.1374 +
1.1375 +/**
1.1376 +@SYMTestCaseID GRAPHICS-FBSERV-0637
1.1377 +@SYMTestPriority High
1.1378 +@SYMTestType UT
1.1379 +@SYMTestStatus Implemented
1.1380 +@SYMPREQ PREQ2678
1.1381 +
1.1382 +@SYMTestCaseDesc
1.1383 + To ensure that opening the glyph data iterator which has already been opened with different font
1.1384 + has no effect on the state of the iterator.
1.1385 +@SYMTestActions
1.1386 + i. Open glyph data iterator on an 2 glyph codes
1.1387 + ii. Try to open the glyph data iterator again with a different font.
1.1388 + iii. Call RFbsGlyphDataIterator::Next() on the iterator and check error code, making the last
1.1389 + glyph code the current iteration.
1.1390 + iv. Call RFbsGlyphDataIterator::Next() again.
1.1391 +@SYMTestExpectedResults
1.1392 + The second attempt to open the glyph data iterator will result an error with code KErrInUse.
1.1393 + The Next() call after this should return KErrNone, signifying the iterator is still open.
1.1394 + The last Next() call should return KErrNotFound, signifying the iterator has iterated
1.1395 + through the two original glyph codes.
1.1396 +*/
1.1397 +void CTFbsGlyphData::TestGlyphDataIteratorOpenTwiceWithDifferentFonts()
1.1398 + {
1.1399 + INFO_PRINTF1(_L("Ensure that opening the glyph data iterator which has already been opened with different font has no effect"));
1.1400 + __UHEAP_MARK;
1.1401 +
1.1402 + RFbsGlyphDataIterator iter;
1.1403 + TInt iterErr = iter.Open(*iFont, iGlyphCodesLatin, 2);
1.1404 + TESTNOERROR(iterErr);
1.1405 +
1.1406 + iterErr = iter.Open(*iFont2, iGlyphCodesLatin, 2);
1.1407 + TESTE(iterErr == KErrInUse, iterErr);
1.1408 + iterErr = iter.Next();
1.1409 + TESTNOERROR(iterErr);
1.1410 + iterErr = iter.Next();
1.1411 + TESTE(iterErr == KErrNotFound, iterErr);
1.1412 + iter.Close();
1.1413 +
1.1414 + __UHEAP_MARKEND;
1.1415 + }
1.1416 +
1.1417 +/**
1.1418 +@SYMTestCaseID GRAPHICS-FBSERV-0638
1.1419 +@SYMTestPriority High
1.1420 +@SYMTestType UT
1.1421 +@SYMTestStatus Implemented
1.1422 +@SYMPREQ PREQ2678
1.1423 +
1.1424 +@SYMTestCaseDesc
1.1425 + To ensure that opening of glyph data iterator with the font greater than
1.1426 + 2048 by 2048 will not be supported
1.1427 +@SYMTestActions
1.1428 + i. Create font with the height greater than 2048
1.1429 + ii. Try to open the glyph data iterator with the font created on previous step
1.1430 + iii Release the font
1.1431 +@SYMTestExpectedResults
1.1432 + Must fail with error code KErrTooBig
1.1433 +*/
1.1434 +void CTFbsGlyphData::TestGlyphDataIteratorOpenTooBigFont()
1.1435 + {
1.1436 + INFO_PRINTF1(_L("To ensure that opening of glyph data iterator with the font greater than 2048X2048 will not be supported"));
1.1437 + __UHEAP_MARK;
1.1438 +
1.1439 + CFbsFont* bigFont;
1.1440 + const TInt maxHeight = 2048;
1.1441 + const TInt maxHeightLimit = maxHeight + 20; //max size after we stop trying to create the font
1.1442 + // the loop below will guarantee that if the font with the size greater than 2048 is available it will be created
1.1443 + for(TInt height = maxHeight + 1; height < maxHeightLimit; height++)
1.1444 + {
1.1445 + TESTNOERROR(iTs->GetNearestFontToDesignHeightInPixels((CFont*&)bigFont, TFontSpec(KTypefaceName, height)));
1.1446 + TInt realHeight = bigFont->FontMaxHeight();
1.1447 + if(realHeight > maxHeight)
1.1448 + {
1.1449 + break;
1.1450 + }
1.1451 + iTs->ReleaseFont(bigFont);
1.1452 + bigFont = NULL;
1.1453 + }
1.1454 +
1.1455 + if (bigFont)
1.1456 + {
1.1457 + RFbsGlyphDataIterator iter;
1.1458 + TInt iterErr = iter.Open(*bigFont, iGlyphCodesLatin, KNumGlyphCodesLatin);
1.1459 + TESTE(iterErr == KErrTooBig, iterErr);
1.1460 + iTs->ReleaseFont(bigFont);
1.1461 + }
1.1462 + else
1.1463 + {
1.1464 + //It is legitimate to fail to create the font, as there are no requirements for the rasterizer here to support such big font.
1.1465 + //In this case we will skip the test.
1.1466 + WARN_PRINTF1(_L("Failed to create font with height greater than 2048"));
1.1467 + }
1.1468 +
1.1469 + __UHEAP_MARKEND;
1.1470 + }
1.1471 +
1.1472 +
1.1473 +
1.1474 +
1.1475 +/**
1.1476 +@SYMTestCaseID GRAPHICS-FBSERV-0640
1.1477 +@SYMTestPriority High
1.1478 +@SYMTestType UT
1.1479 +@SYMTestStatus Implemented
1.1480 +@SYMPREQ PREQ2678
1.1481 +
1.1482 +@SYMTestCaseDesc
1.1483 + To ensure that the glyph data iterator processes wrong arguments correctly
1.1484 +@SYMTestActions
1.1485 + i. Try to open the glyph data iterator with the negative count passed in
1.1486 + ii. Try to open the glyph data iterator with the positive count and NULL
1.1487 + glyph code array pointer passed in
1.1488 + iii. Try to open the glyph data iterator with a valid glyph code array and
1.1489 + count equal to zero
1.1490 +@SYMTestExpectedResults
1.1491 + At all steps the returned value is set to KErrArgument.
1.1492 +*/
1.1493 +void CTFbsGlyphData::TestGlyphDataIteratorOpenWithWrongArgument()
1.1494 + {
1.1495 + INFO_PRINTF1(_L("To ensure that the glyph data iterator processes wrong arguments correctly"));
1.1496 + __UHEAP_MARK;
1.1497 +
1.1498 + RFbsGlyphDataIterator iter;
1.1499 + TInt iterErr = iter.Open(*iFont, iGlyphCodesLatin, -1);
1.1500 + TESTE(iterErr == KErrArgument, iterErr);
1.1501 +
1.1502 + iterErr = iter.Open(*iFont, NULL, 1);
1.1503 + TESTE(iterErr == KErrArgument, iterErr);
1.1504 +
1.1505 + iterErr = iter.Open(*iFont, iGlyphCodesLatin, 0);
1.1506 + TESTE(iterErr == KErrArgument, iterErr);
1.1507 +
1.1508 + __UHEAP_MARKEND;
1.1509 + }
1.1510 +
1.1511 +/**
1.1512 +@SYMTestCaseID GRAPHICS-FBSERV-0641
1.1513 +@SYMTestPriority High
1.1514 +@SYMTestType UT
1.1515 +@SYMTestStatus Implemented
1.1516 +@SYMPREQ PREQ2678
1.1517 +
1.1518 +@SYMTestCaseDesc
1.1519 + To ensure that all allocated RSgImages were released after the
1.1520 + glyph data iterator has been opened and closed multiple times.
1.1521 +
1.1522 +@SYMTestActions
1.1523 + i. Retrieve MSgDriver_Test interface from the SgDriver
1.1524 + ii. Mark alloc start and obtain resorce count from the interface
1.1525 + iii. Iterate through glyph data by calling RFbsGlyphDataIterator::Next()
1.1526 + iv. Retrieve SgImage from the glyph data iterator instance
1.1527 + v. Repeate steps iii and iv multiple times
1.1528 + vi. Release font
1.1529 + vii. Mark alloc end and obtain resorce count from the interface
1.1530 +
1.1531 +@SYMTestExpectedResults
1.1532 + Resorce count at the end matches resorce count at the beginning.
1.1533 +*/
1.1534 +void CTFbsGlyphData::TestGlyphDataIteratorImageMemoryLeak()
1.1535 + {
1.1536 + __UHEAP_MARK;
1.1537 +
1.1538 + MSgDriver_Test* sgDriverTestInterface = NULL;
1.1539 + TInt err = iSgDriver.GetInterface(sgDriverTestInterface);
1.1540 + if(err != KErrNone)
1.1541 + {
1.1542 + __UHEAP_MARKEND;
1.1543 + WARN_PRINTF2(_L("Failed to obtain MSgDriver_Test interface with error code: %d, the test will be skipped"), err);
1.1544 + return;
1.1545 + }
1.1546 +
1.1547 + TEST(sgDriverTestInterface != NULL);
1.1548 + sgDriverTestInterface->AllocMarkStart();
1.1549 +
1.1550 + MSgDriver_Profiling* sgDriverProfilInterface = NULL;
1.1551 + err = iSgDriver.GetInterface(sgDriverProfilInterface);
1.1552 + if(err != KErrNone)
1.1553 + {
1.1554 + sgDriverTestInterface->AllocMarkEnd(0);
1.1555 + __UHEAP_MARKEND;
1.1556 + WARN_PRINTF2(_L("Failed to obtain MSgDriver_Profiling interface with error code: %d, the test will be skipped"), err);
1.1557 + return;
1.1558 + }
1.1559 + const TInt resCount = sgDriverProfilInterface->LocalResourceCount();
1.1560 +
1.1561 + CFbsFont* font = NULL;
1.1562 + err = iTs->GetNearestFontToDesignHeightInPixels((CFont*&)font, TFontSpec(KTypefaceName, 15));
1.1563 + TESTNOERROR(err);
1.1564 + if(err != KErrNone)
1.1565 + {
1.1566 + __UHEAP_MARKEND;
1.1567 + return;
1.1568 + }
1.1569 +
1.1570 + for (TInt ii = 0; ii < 10; ii++)
1.1571 + {
1.1572 + TInt index = 0;
1.1573 + RFbsGlyphDataIterator iter;
1.1574 + TInt iterErr = iter.Open(*font, iGlyphCodesLatin, KNumGlyphCodesLatin);
1.1575 + TESTNOERROR(iterErr);
1.1576 + for (; (iterErr == KErrNone) && (index < KNumGlyphCodesLatin); iterErr = iter.Next(), ++index)
1.1577 + {
1.1578 + const RSgImage& image = iter.Image();
1.1579 + }
1.1580 + iter.Close();
1.1581 + TEST(index == KNumGlyphCodesLatin);
1.1582 + TESTE(iterErr == KErrNotFound, iterErr);
1.1583 + }
1.1584 + iTs->ReleaseFont(font);
1.1585 + const TInt resCountEnd = sgDriverProfilInterface->LocalResourceCount();
1.1586 + TEST(resCountEnd == resCount);
1.1587 + sgDriverTestInterface->AllocMarkEnd(0);
1.1588 +
1.1589 + __UHEAP_MARKEND;
1.1590 + }
1.1591 +
1.1592 +/**
1.1593 +@SYMTestCaseID GRAPHICS-FBSERV-0659
1.1594 +@SYMTestPriority Med
1.1595 +@SYMTestType UT
1.1596 +@SYMTestStatus Implemented
1.1597 +@SYMPREQ PREQ2678
1.1598 +
1.1599 +@SYMTestCaseDesc
1.1600 + Uses the RFbsGlyphDataIterator to render a large amount of unique glyphs, at a very large
1.1601 + size, to ensure that if graphics memory runs out while the iterator is in use, eviction
1.1602 + takes place and does not corrupt the glyph images in any way.
1.1603 +
1.1604 +@SYMTestActions
1.1605 + i. Create a large CFbsFont from the typeface store (size 100+)
1.1606 + ii. Simulate a low graphics-memory situation by creating enough RSgImages to fill the memory,
1.1607 + releasing one image in order to allow some small amount for the test.
1.1608 + iii. Open a RFbsGlyphDataIterator on the font, using a large array of unique glyph codes.
1.1609 + iv. Iterate through the glyphs, comparing each returned SgImage against the system-memory
1.1610 + representation of the glyph as returned by CFont::GetCharacterData().
1.1611 + v. Check for errors and mismatches, and release all images created by ii.
1.1612 +
1.1613 +@SYMTestExpectedResults
1.1614 + At each iteration, each glyph should match in size and contents.
1.1615 +*/
1.1616 +void CTFbsGlyphData::TestGlyphDataIteratorLargeFontStress()
1.1617 + {
1.1618 + INFO_PRINTF1(_L("Stress test using a RFbsGlyphDataIterator with a large font"));
1.1619 +#ifdef __WINS__
1.1620 + // Cannot run test on emulator reliably - this is because on emulator
1.1621 + // system-memory is used for RSgImages, so using up RSgImage memory may
1.1622 + // cause heap-allocation failures unrelated to the area being tested.
1.1623 + // This test is specifically testing the behaviour when running out of
1.1624 + // RSgImage-based memory (i.e. graphics memory), but on emulator this
1.1625 + // will cause a failed allocation anywhere.
1.1626 + INFO_PRINTF1(_L("Skipping test on emulator..."));
1.1627 +#else
1.1628 + 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"));
1.1629 + TEST(EFalse);
1.1630 +/* __UHEAP_MARK;
1.1631 +
1.1632 + const TInt KFontSize = 128;
1.1633 +
1.1634 + CFbsFont* font;
1.1635 + TInt err = iTs->GetNearestFontToDesignHeightInPixels((CFont*&)font, TFontSpec(KMonoTypefaceName, KFontSize));
1.1636 + TESTNOERROR(err);
1.1637 + // Output the actual fontspec used in the test.
1.1638 + InfoPrintFontSpec(*font);
1.1639 +
1.1640 + // Create 2 buffers for use in comparing SgImages so that we don't run out
1.1641 + // of system memory through allocating memory in the test
1.1642 + TInt maxFontWidth = font->MaxCharWidthInPixels();
1.1643 + TInt maxFontHeight = font->HeightInPixels();
1.1644 + iTempBuf1 = (TUint8*) User::AllocZ(maxFontWidth * maxFontHeight);
1.1645 + iTempBuf2 = (TUint8*) User::AllocZ(maxFontWidth * maxFontHeight);
1.1646 +
1.1647 + // In order for the image comparisons to have enough memory to perform, keep
1.1648 + // one large RSgImage which is created before the rest of the graphics memory
1.1649 + // is filled. This image can then be closed before doing the image comparison
1.1650 + // and recreated after the image comparison to ensure that the graphics
1.1651 + // memory is full. Without this image, the image comparison could fail with
1.1652 + // out of memory and the test would fail.
1.1653 + RSgImage tempImage;
1.1654 + TESTNOERROR(tempImage.Create(TSgImageInfo(TSize(1000, 1000), ESgPixelFormatA_8, ESgUsageBitOpenVgImage)));
1.1655 +
1.1656 + TFontSpec actualFontSpec;
1.1657 + actualFontSpec = font->FontSpecInTwips();
1.1658 +
1.1659 + // Create RSgImages from character data independently from using iterator.
1.1660 + // These will be used for comparing with RSgImages retrieved from iterator.
1.1661 + RArray <RSgImage> sgImageFromCharDataArray;
1.1662 + TInt index = 0;
1.1663 + for(; (index < KNumGlyphCodesLatin) && (err == KErrNone); ++index)
1.1664 + {
1.1665 + RSgImage characterDataSgImage;
1.1666 + TInt err = KErrNone;
1.1667 + const TUint8* bitmapData = NULL;
1.1668 + TSize bitmapSize;
1.1669 + TOpenFontCharMetrics metrics;
1.1670 + font->GetCharacterData(iGlyphCodesLatin[index] | KGlyphCodeFlag, metrics, bitmapData, bitmapSize);
1.1671 +
1.1672 + if (bitmapSize != TSize(0, 0))
1.1673 + {
1.1674 + err = CreateSgImageFromCharacterData(bitmapData, bitmapSize, actualFontSpec.iFontStyle.BitmapType(), characterDataSgImage, iTempBuf1, iTempBuf2);
1.1675 + }
1.1676 + if (KErrNone == err)
1.1677 + {
1.1678 + err = sgImageFromCharDataArray.Append(characterDataSgImage);
1.1679 + }
1.1680 + }
1.1681 + TESTNOERROR(err);
1.1682 + TEST(index == KNumGlyphCodesLatin);
1.1683 +
1.1684 + // Simulate low OOGM situation by creating many RSgImages until out of memory.
1.1685 + RArray <RSgImage> sgImageArray;
1.1686 + if (err == KErrNone)
1.1687 + {
1.1688 + TESTNOERROR(NearlyFillGraphicsMemoryWithImages(TSize(256, 256), sgImageArray));
1.1689 + }
1.1690 +
1.1691 + // Open Iterator on long string of data...
1.1692 + RFbsGlyphDataIterator iter;
1.1693 + TInt iterErr = KErrNone;
1.1694 + if (err == KErrNone)
1.1695 + {
1.1696 + iterErr = iter.Open(*font, iGlyphCodesLatin, KNumGlyphCodesLatin);
1.1697 + TESTNOERROR(iterErr);
1.1698 + }
1.1699 +
1.1700 + // For each glyph, compare it to the system-memory version from GetCharacterData().
1.1701 + TInt numMismatches = 0;
1.1702 + for(index = 0; (iterErr == KErrNone) && (index < sgImageFromCharDataArray.Count()) && (err == KErrNone); iterErr = iter.Next(), ++index)
1.1703 + {
1.1704 + const TUint8* bitmapData = NULL;
1.1705 + TSize bitmapSize;
1.1706 + TOpenFontCharMetrics metrics;
1.1707 + font->GetCharacterData(iter.GlyphCode() | KGlyphCodeFlag, metrics, bitmapData, bitmapSize);
1.1708 +
1.1709 + if (iter.Rect().Size() == TSize(0, 0))
1.1710 + {
1.1711 + numMismatches += (bitmapSize != TSize(0, 0)) ? 1 : 0;
1.1712 + }
1.1713 + else
1.1714 + {
1.1715 + // Free up memory so that the image compariso succeeds
1.1716 + // Release all the images used to simulate OOGM.
1.1717 + for (TInt i = sgImageArray.Count() - 1; i >= 0; --i)
1.1718 + {
1.1719 + sgImageArray[i].Close();
1.1720 + sgImageArray.Remove(i);
1.1721 + }
1.1722 +
1.1723 + TBool match = ETrue;
1.1724 + err = CompareSgImages(iEGL, sgImageFromCharDataArray[index], TRect(bitmapSize), iTempBuf1, iter.Image(), iter.Rect(), iTempBuf2, match);
1.1725 + if (err == KErrNone && !match)
1.1726 + {
1.1727 + ++numMismatches;
1.1728 + }
1.1729 + TInt result = FillGraphicsMemoryWithImages(TSize(256, 256), sgImageArray);
1.1730 + TESTE(result == KErrNoMemory || result == KErrNoGraphicsMemory, result);
1.1731 + }
1.1732 + }
1.1733 + iter.Close();
1.1734 +
1.1735 + // Release all images created from character data.
1.1736 + for (TInt i = sgImageFromCharDataArray.Count()-1; i >= 0; --i)
1.1737 + {
1.1738 + sgImageFromCharDataArray[i].Close();
1.1739 + }
1.1740 + sgImageFromCharDataArray.Close();
1.1741 +
1.1742 + // Release all the images used to simulate OOGM.
1.1743 + for (TInt i = sgImageArray.Count() - 1; i >= 0; --i)
1.1744 + {
1.1745 + sgImageArray[i].Close();
1.1746 + }
1.1747 + sgImageArray.Close();
1.1748 + tempImage.Close();
1.1749 + iTs->ReleaseFont(font);
1.1750 + User::Free(iTempBuf1);
1.1751 + User::Free(iTempBuf2);
1.1752 + iTempBuf1 = NULL;
1.1753 + iTempBuf2 = NULL;
1.1754 +
1.1755 + // Log any errors only after memory is freed - this ensures there is enough
1.1756 + // memory for the logger.
1.1757 + TESTNOERROR(err);
1.1758 + TESTE(iterErr == KErrNotFound, iterErr);
1.1759 + TEST(index == KNumGlyphCodesLatin);
1.1760 + TEST(numMismatches == 0);
1.1761 +
1.1762 + __UHEAP_MARKEND;*/
1.1763 +#endif
1.1764 + }
1.1765 +
1.1766 +/**
1.1767 +@SYMTestCaseID GRAPHICS-FBSERV-0660
1.1768 +@SYMTestPriority Med
1.1769 +@SYMTestType UT
1.1770 +@SYMTestStatus Implemented
1.1771 +@SYMPREQ PREQ2678
1.1772 +
1.1773 +@SYMTestCaseDesc
1.1774 + Opens an RFbsGlyphDataIterator on many different fonts of different sizes and typefaces
1.1775 + and uses many fonts, in order to test that the iterator can cope with being used on many
1.1776 + fonts with many glyphs.
1.1777 +
1.1778 +@SYMTestActions
1.1779 + i. Perform test of 100 iterations, where:
1.1780 + 1. A new Latin font is created every iteration in order to force the Typeface Store
1.1781 + to create a brand-new server-side font at each iteration.
1.1782 + 2. For this font, open an RFbsGlyphDataIterator and cycle through all Latin glyphs.
1.1783 + 3. For each glyph, compare against the glyph image returned by CFont::GetCharacterData().
1.1784 + 4. Keep a record of the number of mismatches, and carry on to next font.
1.1785 + ii. Perform i. again, but using the existing fonts.
1.1786 + iii. Check that there are no mismatches, all glyphs and fonts were successfully checked,
1.1787 + and no error codes returned during the test.
1.1788 + iv. Clean up all resources.
1.1789 +
1.1790 +@SYMTestExpectedResults
1.1791 + The glyphs provided by the iterator should match that returned by GetCharacterData()
1.1792 + for every font and every iteration.
1.1793 +*/
1.1794 +void CTFbsGlyphData::TestGlyphDataIteratorManyFontsStressL()
1.1795 + {
1.1796 + INFO_PRINTF1(_L("Stress test using a RFbsGlyphDataIterator with hundreds of fonts"));
1.1797 + 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"));
1.1798 + TEST(EFalse);
1.1799 + /*__UHEAP_MARK;
1.1800 +
1.1801 + const TInt KNumFonts = 100;
1.1802 + const TInt KNumRepeatsPerFont = 2;
1.1803 + TInt err = KErrNone;
1.1804 + TInt numGlyphMismatches = 0;
1.1805 +
1.1806 + CFbsFont** font = new (ELeave) CFbsFont*[KNumFonts];
1.1807 + Mem::FillZ(font, sizeof(CFbsFont*) * KNumFonts);
1.1808 +
1.1809 + // Do the whole thing KNumRepeatsPerFont times. The second+ repeats will
1.1810 + // re-use the fonts created in the first repeat, to ensure that fonts that
1.1811 + // may have been evicted are able to be re-used with the iterator.
1.1812 + for (TInt rep = 0; (rep < KNumRepeatsPerFont) && (err == KErrNone); ++rep)
1.1813 + {
1.1814 + // Iterate through all the font variants:
1.1815 + // Iterate all font styles, for all latin typefaces, at increasing sizes.
1.1816 + TInt i = 0;
1.1817 + for (; (i < KNumFonts) && (err == KErrNone); ++i)
1.1818 + {
1.1819 + // Only create this font if this font isn't already valid (i.e. when this is the
1.1820 + // first rep) otherwise re-use it.
1.1821 + if (!font[i])
1.1822 + {
1.1823 + TFontSpec requestedFontSpec = GenerateDejaVuFontSpec(i);
1.1824 + err = iTs->GetNearestFontToDesignHeightInPixels((CFont*&)font[i], requestedFontSpec);
1.1825 + }
1.1826 + if (err == KErrNone)
1.1827 + {
1.1828 + RFbsGlyphDataIterator iter;
1.1829 + TInt iterErr = iter.Open(*(font[i]), iGlyphCodesLatin, KNumGlyphCodesLatin);
1.1830 + if (iterErr != KErrNone)
1.1831 + {
1.1832 + ERR_PRINTF2(_L("Failed to open RFbsGlyphDataIterator [err=%d]"), iterErr);
1.1833 + InfoPrintFontSpec(*(font[i]));
1.1834 + iStep->SetTestStepResult(EFail);
1.1835 + }
1.1836 + else
1.1837 + {
1.1838 + TInt index = 0;
1.1839 + for(; (iterErr == KErrNone) && (index < KNumGlyphCodesLatin) && (err == KErrNone) ; iterErr = iter.Next(), index++)
1.1840 + {
1.1841 + const TUint8* bitmapData = NULL;
1.1842 + TSize bitmapSize;
1.1843 + TOpenFontCharMetrics metrics;
1.1844 + font[i]->GetCharacterData(iter.GlyphCode() | KGlyphCodeFlag, metrics, bitmapData, bitmapSize);
1.1845 + if (iter.Rect().Size() == TSize(0, 0))
1.1846 + {
1.1847 + numGlyphMismatches += (bitmapSize != TSize(0, 0)) ? 1 : 0;
1.1848 + }
1.1849 + else
1.1850 + {
1.1851 + TBool match = EFalse;
1.1852 + const TFontSpec fontSpec = font[i]->FontSpecInTwips();
1.1853 + // Compare to system-memory version of glyph
1.1854 + RSgImage characterDataImage;
1.1855 + err = CreateSgImageFromCharacterData(bitmapData, bitmapSize, fontSpec.iFontStyle.BitmapType(), characterDataImage);
1.1856 + if (err == KErrNone)
1.1857 + {
1.1858 + err = CompareSgImages(iEGL, iter.Image(), iter.Rect(), characterDataImage, TRect(bitmapSize), match);
1.1859 + }
1.1860 + if (err == KErrNone && !match)
1.1861 + {
1.1862 + ++numGlyphMismatches;
1.1863 + }
1.1864 + characterDataImage.Close();
1.1865 + }
1.1866 + }
1.1867 + iter.Close();
1.1868 + TESTE(iterErr == KErrNotFound, iterErr);
1.1869 + TEST(index == KNumGlyphCodesLatin);
1.1870 + }
1.1871 + }
1.1872 + }
1.1873 + // Check all the fonts were iterated through.
1.1874 + TEST(i == KNumFonts);
1.1875 + }
1.1876 + TESTNOERROR(err);
1.1877 + TEST(numGlyphMismatches == 0);
1.1878 +
1.1879 + // Cleanup
1.1880 + for (TInt ii = 0; ii < KNumFonts; ii++)
1.1881 + {
1.1882 + iTs->ReleaseFont(font[ii]);
1.1883 + }
1.1884 + delete [] font;
1.1885 + __UHEAP_MARKEND;*/
1.1886 + }
1.1887 +
1.1888 +/**
1.1889 +@SYMTestCaseID GRAPHICS-FBSERV-0662
1.1890 +@SYMTestPriority Low
1.1891 +@SYMTestType UT
1.1892 +@SYMTestStatus Implemented
1.1893 +@SYMPREQ PREQ2678
1.1894 +
1.1895 +@SYMTestCaseDesc
1.1896 + Uses a RFbsGlyphDataIterator when there is no graphics memory available in the system.
1.1897 + It shows that when under low graphics memory, Next() returns the correct error code
1.1898 + as per the API (either KErrNoMemory or KErrNoGraphicsMemory, depending on the implementation
1.1899 + of Graphics Resource being used).
1.1900 +
1.1901 +@SYMTestActions
1.1902 + i. Create a CFbsFont from the typeface store.
1.1903 + ii. Simulate a low graphics-memory situation by creating enough RSgImages to fill the memory,
1.1904 + iii. Open a RFbsGlyphDataIterator on the font.
1.1905 + iv. Attempt to use the iterator, calling Next(), checking the returned code.
1.1906 + v. Close the iterator and release all graphics memory from ii.
1.1907 +
1.1908 +@SYMTestExpectedResults
1.1909 + Next() should return either KErrNoMemory or KErrNoGraphicsMemory depending on the implmentation
1.1910 + of Graphics Resource used. It should return the same error as is returned when filling
1.1911 + the graphics memory reaches the limit.
1.1912 +*/
1.1913 +void CTFbsGlyphData::TestGlyphDataIteratorNoGraphicsMemory()
1.1914 + {
1.1915 + INFO_PRINTF1(_L("Test that when there is no GPU memory available, Next() returns correct error"));
1.1916 + 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"));
1.1917 + TEST(EFalse);
1.1918 + /*__UHEAP_MARK;
1.1919 +
1.1920 + const TInt KFontSize = 128;
1.1921 + CFbsFont* font = NULL;
1.1922 + RFbsGlyphDataIterator iter;
1.1923 +
1.1924 + TInt err = iTs->GetNearestFontToDesignHeightInPixels((CFont*&)font, TFontSpec(KMonoTypefaceName, KFontSize));
1.1925 + TESTNOERROR(err);
1.1926 +
1.1927 + // Simulate low OOGM situation by creating many RSgImages until out of memory.
1.1928 + if (err == KErrNone)
1.1929 + {
1.1930 + InfoPrintFontSpec(*font);
1.1931 + RArray <RSgImage> sgImageArray;
1.1932 + TInt iterErr = KErrNone;
1.1933 + TInt gfxMemErr = FillGraphicsMemoryWithImages(TSize(KFontSize, KFontSize), sgImageArray);
1.1934 + TESTE(gfxMemErr == KErrNoMemory || gfxMemErr == KErrNoGraphicsMemory, gfxMemErr);
1.1935 + if (gfxMemErr == KErrNoMemory || gfxMemErr == KErrNoGraphicsMemory)
1.1936 + {
1.1937 + // Next() could either fail with KErrNoMemory or KErrNoGraphicsMemory, but should
1.1938 + // be the same error code as the last attempted creation of an SgImage, done in
1.1939 + // FillGraphicsMemoryWithImages() so compare against that code.
1.1940 + iterErr = iter.Open(*font, iGlyphCodesLatin, KNumGlyphCodesLatin);
1.1941 + for (; iterErr == KErrNone; iterErr = iter.Next())
1.1942 + {
1.1943 + // no operation
1.1944 + }
1.1945 + iter.Close();
1.1946 + }
1.1947 +
1.1948 + // Release all the images used to simulate OOGM.
1.1949 + for (TInt i = sgImageArray.Count() - 1; i >= 0; --i)
1.1950 + {
1.1951 + sgImageArray[i].Close();
1.1952 + }
1.1953 + sgImageArray.Close();
1.1954 +
1.1955 + // Log any errors only after memory is freed - this ensures there is enough
1.1956 + // memory for the logger.
1.1957 + TESTE(iterErr == gfxMemErr, iterErr);
1.1958 + }
1.1959 +
1.1960 + iTs->ReleaseFont(font);
1.1961 +
1.1962 + __UHEAP_MARKEND;*/
1.1963 + }
1.1964 +
1.1965 +/**
1.1966 +@SYMTestCaseID GRAPHICS-FBSERV-0666
1.1967 +@SYMTestPriority Low
1.1968 +@SYMTestType UT
1.1969 +@SYMTestStatus Implemented
1.1970 +@SYMPREQ PREQ2678
1.1971 +
1.1972 +@SYMTestCaseDesc
1.1973 + Uses a RFbsGlyphDataIterator after Next() returns an error, in order to show that
1.1974 + an error does not invalidate the state of the iterator and it is still usable.
1.1975 +
1.1976 +@SYMTestActions
1.1977 + i. Open the RFbsGlyphDataIterator on 1 glyph code.
1.1978 + ii. Store the data of the iterator and call Next() to reach the end of the iterator
1.1979 + iii. Access the glyph data repeatedly and check that the iterator members
1.1980 + still match those in ii.
1.1981 +
1.1982 +@SYMTestExpectedResults
1.1983 + The calls to Next() should cause KErrNotFound since it is past the final glyph.
1.1984 + The iterator data should match at all times since the iterator is never moved.
1.1985 +*/
1.1986 +void CTFbsGlyphData::TestGlyphDataIteratorNextIsAtomic()
1.1987 + {
1.1988 + INFO_PRINTF1(_L("To ensure that Next() is atomic, if it returns an error it is still useable"));
1.1989 + __UHEAP_MARK;
1.1990 +
1.1991 + RFbsGlyphDataIterator iter;
1.1992 + TInt iterErr = iter.Open(*iFont, iGlyphCodesLatin, 1);
1.1993 + TESTNOERROR(iterErr);
1.1994 +
1.1995 + TSgDrawableId id = iter.Image().Id();
1.1996 + TOpenFontCharMetrics metrics = iter.Metrics();
1.1997 + TUint glyphCode = iter.GlyphCode();
1.1998 + TRect rect = iter.Rect();
1.1999 +
1.2000 + for (TInt i = 0; i < 2; i++)
1.2001 + {
1.2002 + iterErr = iter.Next();
1.2003 + TESTE(iterErr == KErrNotFound, iterErr);
1.2004 +
1.2005 + TEST(id == iter.Image().Id());
1.2006 + TEST(glyphCode == iter.GlyphCode());
1.2007 + TEST(rect == iter.Rect());
1.2008 + TEST(CompareMetrics(metrics, iter.Metrics()) == 0);
1.2009 + }
1.2010 + iter.Close();
1.2011 +
1.2012 + __UHEAP_MARKEND;
1.2013 + }
1.2014 +
1.2015 +/**
1.2016 +@SYMTestCaseID GRAPHICS-FBSERV-0665
1.2017 +@SYMTestPriority High
1.2018 +@SYMTestType UT
1.2019 +@SYMTestStatus Implemented
1.2020 +@SYMPREQ PREQ2678
1.2021 +
1.2022 +@SYMTestCaseDesc
1.2023 + Glyph Atlas white-box test.
1.2024 + To ensure that the same RSgImage is used for repeated requests for the
1.2025 + same glyph in the same call to RFbsGlyphDataIterator:Open().
1.2026 +@SYMTestActions
1.2027 + i Open the glyph data iterator with a list of glyph codes which are all the same
1.2028 + ii Retrieve the drawable id of each iteration
1.2029 + iii Check that the same drawable id is retrieved in each iteration
1.2030 +@SYMTestExpectedResults
1.2031 + Each iteration returns the same drawable id.
1.2032 +*/
1.2033 +void CTFbsGlyphData::TestGlyphDataIteratorSameGlyphCodes()
1.2034 + {
1.2035 + 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()"));
1.2036 + __UHEAP_MARK;
1.2037 +
1.2038 + const TUint KSameRepeatedGlyphCode = iGlyphCodesLatin['A' - 0x20];
1.2039 + const TInt KNumGlyphs = 10;
1.2040 + TUint* sameRepeatedGlyphCodes = new TUint[KNumGlyphs];
1.2041 + for (TInt ii = 0; ii < KNumGlyphs; ++ii)
1.2042 + {
1.2043 + sameRepeatedGlyphCodes[ii] = KSameRepeatedGlyphCode;
1.2044 + }
1.2045 + RFbsGlyphDataIterator iter;
1.2046 + TInt err = iter.Open(*iFont, sameRepeatedGlyphCodes, KNumGlyphs);
1.2047 +
1.2048 + TESTNOERROR(err);
1.2049 + if (KErrNone == err)
1.2050 + {
1.2051 + // get the drawable id of the first glyph and check that the id is valid
1.2052 + TSgDrawableId referenceId = iter.Image().Id();
1.2053 + RSgImage image;
1.2054 + TESTNOERROR(image.Open(referenceId));
1.2055 + image.Close();
1.2056 + TESTNOERROR(iter.Next());
1.2057 +
1.2058 + for (;KErrNone == err; err = iter.Next())
1.2059 + {
1.2060 + TEST(referenceId == iter.Image().Id());
1.2061 + }
1.2062 + TESTE(KErrNotFound == err, err);
1.2063 + }
1.2064 +
1.2065 + iter.Close();
1.2066 + delete[] sameRepeatedGlyphCodes;
1.2067 +
1.2068 + __UHEAP_MARKEND;
1.2069 + }
1.2070 +
1.2071 +/**
1.2072 +@SYMTestCaseID GRAPHICS-FBSERV-0668
1.2073 +@SYMTestPriority High
1.2074 +@SYMTestType UT
1.2075 +@SYMTestStatus Implemented
1.2076 +@SYMPREQ PREQ2678
1.2077 +
1.2078 +@SYMTestCaseDesc
1.2079 + To ensure that the iterator can successfully be opened on an array
1.2080 + of glyph codes of various array sizes.
1.2081 +@SYMTestActions
1.2082 + Perform many iterations of opening an array and cycling through the glyphs,
1.2083 + increasing the size of the array after each iteration. Some simple sanity-checking
1.2084 + of the glyphs is performed.
1.2085 +@SYMTestExpectedResults
1.2086 + KErrNone should be returned at all times.
1.2087 +*/
1.2088 +void CTFbsGlyphData::TestGlyphDataIteratorManyArraySizes()
1.2089 + {
1.2090 + INFO_PRINTF1(_L("Ensure that the RFbsGlyphDataIterator successfully opens glyph code arrays of many sizes"));
1.2091 + __UHEAP_MARK;
1.2092 +
1.2093 + RFbsGlyphMetricsArray glyphMetricsArray;
1.2094 +
1.2095 + TESTNOERROR(glyphMetricsArray.Get(*iFont, iGlyphCodesLatin, KNumGlyphCodesLatin));
1.2096 + TInt iterErr = KErrNone;
1.2097 +
1.2098 + for (TInt arraySize = 1; (arraySize < KNumGlyphCodesLatin) && (iterErr == KErrNone); ++arraySize)
1.2099 + {
1.2100 + RFbsGlyphDataIterator iter;
1.2101 + TInt iterErr = iter.Open(*iFont, iGlyphCodesLatin, arraySize);
1.2102 + TESTNOERROR(iterErr);
1.2103 +
1.2104 + for (TInt index = 0; iterErr == KErrNone; iterErr = iter.Next(), ++index)
1.2105 + {
1.2106 + // sanity checking...
1.2107 + if (iter.GlyphCode() != iGlyphCodesLatin[index])
1.2108 + {
1.2109 + ERR_PRINTF4(_L("Test failed at array size %d - Wanted glyphcode %d, got %d"), arraySize, iGlyphCodesLatin[index], iter.GlyphCode());
1.2110 + iStep->SetTestStepResult(EFail);
1.2111 + }
1.2112 + if (CompareMetrics(iter.Metrics(), glyphMetricsArray[index]) != 0)
1.2113 + {
1.2114 + ERR_PRINTF3(_L("Test failed at array size %d, metrics check failed at glyphcode %d"), arraySize, iGlyphCodesLatin[index]);
1.2115 + iStep->SetTestStepResult(EFail);
1.2116 + }
1.2117 + }
1.2118 + iter.Close();
1.2119 + }
1.2120 +
1.2121 + glyphMetricsArray.Close();
1.2122 + TESTNOERROR(iterErr);
1.2123 +
1.2124 + __UHEAP_MARKEND;
1.2125 + }
1.2126 +
1.2127 +/**
1.2128 +@SYMTestCaseID GRAPHICS-FBSERV-0669
1.2129 +@SYMTestPriority Low
1.2130 +@SYMTestType UT
1.2131 +@SYMTestStatus Implemented
1.2132 +@SYMPREQ PREQ2678
1.2133 +
1.2134 +@SYMTestCaseDesc
1.2135 + Negative test case to show that RFbsGlyphDataIterator and RFbsGlyphMetricsArray
1.2136 + do not support bitmap fonts.
1.2137 +@SYMTestActions
1.2138 + i. Load a bitmap font.
1.2139 + ii. Attempt to open an RFbsGlyphDataIterator and RFbsGlyphMetricsArray with the font.
1.2140 +@SYMTestExpectedResults
1.2141 + KErrNotSupported should be returned in both instances.
1.2142 +*/
1.2143 + void CTFbsGlyphData::TestBitmapFontSupport()
1.2144 + {
1.2145 + INFO_PRINTF1(_L("Test bitmap font not supported"));
1.2146 + __UHEAP_MARK;
1.2147 +
1.2148 + CFbsFont* bitmapFont = NULL;
1.2149 + TInt err = iTs->GetNearestFontToDesignHeightInPixels((CFont*&)bitmapFont, TFontSpec(_L("Digital"), 14));
1.2150 + TESTNOERROR(err);
1.2151 + TEST(!bitmapFont->IsOpenFont());
1.2152 +
1.2153 + RFbsGlyphDataIterator iter;
1.2154 + err = iter.Open(*bitmapFont, iGlyphCodesLatin, KNumGlyphCodesLatin);
1.2155 + TEST(err == KErrNotSupported);
1.2156 + iter.Close();
1.2157 +
1.2158 + RFbsGlyphMetricsArray array;
1.2159 + err = array.Get(*bitmapFont, iGlyphCodesLatin, KNumGlyphCodesLatin);
1.2160 + TEST(err == KErrNotSupported);
1.2161 + array.Close();
1.2162 +
1.2163 + iTs->ReleaseFont(bitmapFont);
1.2164 + __UHEAP_MARKEND;
1.2165 + }
1.2166 +
1.2167 +/**
1.2168 +@SYMTestCaseID GRAPHICS-FBSERV-0671
1.2169 +@SYMTestPriority High
1.2170 +@SYMTestType UT
1.2171 +@SYMTestStatus Implemented
1.2172 +@SYMPREQ PREQ2678
1.2173 +
1.2174 +@SYMTestCaseDesc
1.2175 + Shows that different threads (and therefore RFbsSessions) using fonts with the same
1.2176 + TFontSpec share the same glyphs in the atlas and do not create duplicate entries
1.2177 + in the Glyph Atlas, and that releasing a font clears all associated glyphs in the
1.2178 + atlas.
1.2179 +
1.2180 +@SYMTestActions
1.2181 + i. Create a handle to a test font in the current process.
1.2182 + ii. Spawn a test thread and wait for it to complete. Within the thread :
1.2183 + 1. Create a font with the same fontspec as the parent process.
1.2184 + 2. Use the RFbsGlyphDataIterator API to force rasterization into the glyph atlas.
1.2185 + 3. Release the iterator.
1.2186 + iii. Check there were no leaves from the thread.
1.2187 + iv. Repeat ii. and iii. several times. Before using RFbsGlyphDataIterator,
1.2188 + the thread checks that the glyphs are still in the atlas from the first thread.
1.2189 + v. Check that the number of fonts in the atlas has increased by one only.
1.2190 + vi. Check that the number of glyphs in the atlas has increased by the size of the
1.2191 + glyph code array.
1.2192 + vii. Release the font in the parent process, thereby releasing the font and glyphs
1.2193 + in the glyph atlas, and check that the state of the atlas is the same as before
1.2194 + the test is run.
1.2195 +
1.2196 +@SYMTestExpectedResults
1.2197 + All threads should return no errors or leaves or panics.
1.2198 + After all threads have finished:
1.2199 + The glyph count should have increased by the size of the glyph code array used
1.2200 + in the RFbsGlyphDataIterator, showing that glyphs are only being added to the atlas
1.2201 + once. The number of fonts in the atlas should have increased by one, showing
1.2202 + that only the single underlying font object is being added to the atlas, despite
1.2203 + different RFbsSessions and CFbsFont instances used.
1.2204 + After the test font is released in the main process:
1.2205 + The glyph count and font count return to the pre-test value, showing that when
1.2206 + the last handle to a TFontSpec is released, the atlas frees its associated data.
1.2207 +*/
1.2208 +void CTFbsGlyphData::TestMultithreadShareSingleFont()
1.2209 + {
1.2210 + INFO_PRINTF1(_L("Test glyphs shared between RFbsSessions/threads/processes"));
1.2211 +#ifndef _DEBUG
1.2212 + // Test relies on debug-only FBS messages EFbsMessAtlasGlyphCount and EFbsMessAtlasFontCount
1.2213 + INFO_PRINTF1(_L("Skipping test in release mode"));
1.2214 +#else
1.2215 + __UHEAP_MARK;
1.2216 +
1.2217 + _LIT(KThreadName, "GlyphDataTestThread");
1.2218 + const TInt KNumTestThreads = 5;
1.2219 + const TFontSpec KTestFontSpec(KTypefaceName, 50);
1.2220 + const TInt atlasFontCountStart = iFbs->SendCommand(EFbsMessAtlasFontCount);
1.2221 + const TInt atlasGlyphCountStart = iFbs->SendCommand(EFbsMessAtlasGlyphCount);
1.2222 +
1.2223 + CFbsFont* testFont;
1.2224 + TInt err = iTs->GetNearestFontToDesignHeightInPixels( (CFont*&)testFont, KTestFontSpec);
1.2225 + if (err != KErrNone)
1.2226 + {
1.2227 + ERR_PRINTF2(_L("Could not load font, err = %d"), err);
1.2228 + iStep->SetTestStepResult(EFail);
1.2229 + return;
1.2230 + }
1.2231 +
1.2232 + // Check there are no glyphs belonging to the test font before the test starts.
1.2233 + TInt atlasFontGlyphCount = iFbs->SendCommand(EFbsMessAtlasGlyphCount, testFont->Handle());
1.2234 + TEST(atlasFontGlyphCount == 0);
1.2235 +
1.2236 + TGlyphDataMultithreadParams params = {KTestFontSpec, iGlyphCodesLatin, KNumGlyphCodesLatin, NULL};
1.2237 +
1.2238 + // Run the test threads sequentially, and check its exit status.
1.2239 + RThread testThread;
1.2240 + TInt numThreadsPassed = 0;
1.2241 + for (TInt i = 0; i < KNumTestThreads; i++)
1.2242 + {
1.2243 + TBool threadPassed = ETrue;
1.2244 + TGlyphDataThreadInfo info = {EGlyphDataMultiSessionTestShareGlyphs, params, i, iStep};
1.2245 + err = testThread.Create(KThreadName, CTFbsGlyphData::ThreadFunction, KDefaultStackSize, KTestThreadMinHeapSize, KTestThreadMaxHeapSize, &info);
1.2246 + TESTNOERROR(err);
1.2247 +
1.2248 + TRequestStatus statusThread;
1.2249 + testThread.Logon(statusThread);
1.2250 + testThread.Resume();
1.2251 +
1.2252 + User::WaitForRequest(statusThread);
1.2253 + TInt threadResult = testThread.ExitReason();
1.2254 + if (threadResult != KErrNone)
1.2255 + {
1.2256 + ERR_PRINTF3(_L("Thread %i: Terminated with reason %d"), i, threadResult);
1.2257 + threadPassed = EFalse;
1.2258 + }
1.2259 + TExitCategoryName exitCategory = testThread.ExitCategory();
1.2260 + if (exitCategory.Compare(_L("Kill")) != 0)
1.2261 + {
1.2262 + ERR_PRINTF3(_L("Thread %i: Terminated with reason category '%S'"), i, &exitCategory);
1.2263 + threadPassed = EFalse;
1.2264 + }
1.2265 + testThread.Close();
1.2266 + numThreadsPassed += (threadPassed) ? 1 : 0;
1.2267 + }
1.2268 + TEST(numThreadsPassed == KNumTestThreads);
1.2269 +
1.2270 + // Check that the atlas still contains the glyphs and the font created by the threads
1.2271 + // after they have died, since the font is still open in this process.
1.2272 + atlasFontGlyphCount = iFbs->SendCommand(EFbsMessAtlasGlyphCount, testFont->Handle());
1.2273 + TEST(atlasFontGlyphCount == params.iGlyphCodesCount);
1.2274 + TInt atlasFontCount = iFbs->SendCommand(EFbsMessAtlasFontCount);
1.2275 + TEST(atlasFontCount == (atlasFontCountStart + 1));
1.2276 +
1.2277 + iTs->ReleaseFont(testFont);
1.2278 + testFont = NULL;
1.2279 +
1.2280 + // Check the atlas state is now the same as it was before the test started,
1.2281 + // now that the last remaining handle to the font used in the threads is released.
1.2282 + TInt atlasGlyphCountEnd = iFbs->SendCommand(EFbsMessAtlasGlyphCount);
1.2283 + TEST(atlasGlyphCountStart == atlasGlyphCountEnd);
1.2284 + TInt atlasFontCountEnd = iFbs->SendCommand(EFbsMessAtlasFontCount);
1.2285 + TEST(atlasFontCountStart == atlasFontCountEnd);
1.2286 + __UHEAP_MARKEND;
1.2287 +#endif
1.2288 + }
1.2289 +
1.2290 +/**
1.2291 +Worker thread for TestMultithreadShareSingleFont().
1.2292 +The thread uses RFbsGlyphDataIterator on a CFbsFont of the given TFontSpec.
1.2293 +Once complete the atlas is queried for the number of associated glyphs.
1.2294 + */
1.2295 +void CTFbsGlyphData::ThreadShareGlyphsL(TInt aThreadNum, TGlyphDataMultithreadParams& aParam, CTestStep* aStep)
1.2296 + {
1.2297 + User::LeaveIfError(RFbsSession::Connect());
1.2298 + CFbsTypefaceStore* ts = CFbsTypefaceStore::NewL(NULL);
1.2299 + CleanupStack::PushL(ts);
1.2300 + RFbsSession* fbs = RFbsSession::GetSession();
1.2301 +
1.2302 + CFbsFont* font;
1.2303 + TInt err = ts->GetNearestFontToDesignHeightInPixels((CFont*&)font, aParam.iFontSpec);
1.2304 + User::LeaveIfError(err);
1.2305 +
1.2306 + if (aThreadNum > 0)
1.2307 + {
1.2308 + // If this is not the first thread, it means the first thread has already executed and
1.2309 + // populated the glyph atlas with the glyphs. The font created by this thread
1.2310 + // should already have its glyphs in the atlas.
1.2311 + TInt fontGlyphCount = fbs->SendCommand(EFbsMessAtlasGlyphCount, font->Handle());
1.2312 + if (fontGlyphCount != aParam.iGlyphCodesCount)
1.2313 + {
1.2314 + aStep->ERR_PRINTF4(_L("Thread %d: Only %d glyphs in atlas before first iteration, expected %d"), aThreadNum, fontGlyphCount, aParam.iGlyphCodesCount);
1.2315 + aStep->SetTestStepResult(EFail);
1.2316 + }
1.2317 + }
1.2318 +
1.2319 + RFbsGlyphDataIterator iter;
1.2320 + for (err = iter.Open(*font, aParam.iGlyphCodes, aParam.iGlyphCodesCount); err == KErrNone; err = iter.Next())
1.2321 + {
1.2322 + // no-op
1.2323 + }
1.2324 + iter.Close();
1.2325 +
1.2326 + // Check that the glyphs of this font have been added to the atlas
1.2327 + TInt fontGlyphCount = fbs->SendCommand(EFbsMessAtlasGlyphCount, font->Handle());
1.2328 + if (fontGlyphCount != aParam.iGlyphCodesCount)
1.2329 + {
1.2330 + aStep->ERR_PRINTF5(_L("Thread %d: Only %d glyphs in atlas after last iteration, expected %d (err=%d)"), aThreadNum, fontGlyphCount, aParam.iGlyphCodesCount, err);
1.2331 + aStep->SetTestStepResult(EFail);
1.2332 + }
1.2333 + if (err != KErrNotFound)
1.2334 + {
1.2335 + aStep->ERR_PRINTF3(_L("Thread %d: Error during test = %d"), aThreadNum, err);
1.2336 + aStep->SetTestStepResult(EFail);
1.2337 + }
1.2338 +
1.2339 + ts->ReleaseFont(font);
1.2340 + CleanupStack::PopAndDestroy(1); // ts
1.2341 + RFbsSession::Disconnect();
1.2342 + }
1.2343 +
1.2344 +
1.2345 +/**
1.2346 +@SYMTestCaseID GRAPHICS-FBSERV-0672
1.2347 +@SYMTestPriority Medium
1.2348 +@SYMTestType UT
1.2349 +@SYMTestStatus Implemented
1.2350 +@SYMPREQ PREQ2678
1.2351 +
1.2352 +@SYMTestCaseDesc
1.2353 + Tests that with many concurrent sessions connected to Fbserv, the atlas successfully
1.2354 + returns the correct glyph images even if the atlas becomes full and has to evict glyphs.
1.2355 +
1.2356 +@SYMTestActions
1.2357 + i. Create 25 threads, each a unique session with Fbserv.
1.2358 + ii. Launch the threads simultaneously. In each thread:
1.2359 + 1. Create a FBS typeface store and create a font which is unique in the process.
1.2360 + 2. Use RFbsGlyphDataIterator to iterate through the latin glyph codes.
1.2361 + 3. Check the image is correct for each glyph against the image returned by
1.2362 + CFont::GetCharacterData().
1.2363 + 4. Close the iterator.
1.2364 + 5. Release the font and close the typeface store.
1.2365 + iii. Once all threads have finished, check the exit status of each thread
1.2366 +
1.2367 +@SYMTestExpectedResults
1.2368 + Every glyph for every thread should match the image returned by GetCharacterData()
1.2369 + All threads should exit normally with no Leave code.
1.2370 +*/
1.2371 +_LIT(KTestMultithreadStressFinishSemaphore, "TestMultithreadStressAtlasFinish");
1.2372 +
1.2373 +void CTFbsGlyphData::TestMultithreadStressAtlas()
1.2374 + {
1.2375 + INFO_PRINTF1(_L("Stress test glyph atlas with multiple RFbsSessions"));
1.2376 + WARN_PRINTF1(_L("---Stress test TO BE REVISITED due to Broadcom defect ESLM-85NEFT - TB10.1 eglCreateImageKHR hangs during multithreading"));
1.2377 + TEST(EFalse);
1.2378 + /*__UHEAP_MARK;
1.2379 +
1.2380 + TInt err = KErrNone;
1.2381 + const TInt KNumTestThreads = 25;
1.2382 + _LIT(KThreadNameFormat, "GlyphDataTestThread%i");
1.2383 +
1.2384 + // Create a semaphore that is signalled by each test thread when it has finished.
1.2385 + RSemaphore threadFinishSemaphore;
1.2386 + err = threadFinishSemaphore.CreateGlobal(KTestMultithreadStressFinishSemaphore, 0, EOwnerThread);
1.2387 + TESTNOERROR(err);
1.2388 +
1.2389 + // Prepare the testdata for the threads
1.2390 + // Each thread will have a TFontSpec which will cause unique CFbsFonts
1.2391 + // to be created in the server, and therefore the atlas.
1.2392 + RThread testThread[KNumTestThreads];
1.2393 + TGlyphDataThreadInfo testInfo[KNumTestThreads];
1.2394 + for (TInt i = 0; i < KNumTestThreads; ++i)
1.2395 + {
1.2396 + testInfo[i].iStep = iStep;
1.2397 + testInfo[i].iTest = EGlyphDataMultiSessionTestStressAtlas;
1.2398 + testInfo[i].iParams.iFontSpec = GenerateDejaVuFontSpec(i);
1.2399 + testInfo[i].iParams.iGlyphCodes = iGlyphCodesLatin;
1.2400 + testInfo[i].iParams.iGlyphCodesCount = KNumGlyphCodesLatin;
1.2401 + testInfo[i].iParams.iEGL = iEGL;
1.2402 + testInfo[i].iThreadNum = i;
1.2403 + TBuf<128> threadName;
1.2404 + threadName.AppendFormat(KThreadNameFormat, i);
1.2405 + err = testThread[i].Create(threadName, CTFbsGlyphData::ThreadFunction, KDefaultStackSize, KTestThreadMinHeapSize, KTestThreadMaxHeapSize, &testInfo[i]);
1.2406 + TESTNOERROR(err);
1.2407 + }
1.2408 +
1.2409 + // All threads are created, start them simultaneously.
1.2410 + for (TInt i = 0; i < KNumTestThreads; ++i)
1.2411 + {
1.2412 + testThread[i].Resume();
1.2413 + }
1.2414 + // Wait for all threads to finish.
1.2415 + for (TInt i = 0; i < KNumTestThreads; ++i)
1.2416 + {
1.2417 + threadFinishSemaphore.Wait();
1.2418 + }
1.2419 + // Allow some time for remaining threads to finish tidy-up.
1.2420 + User::After(100000);
1.2421 + threadFinishSemaphore.Close();
1.2422 +
1.2423 + TInt numThreadsPassed = 0;
1.2424 + for (TInt i = 0; i < KNumTestThreads; ++i)
1.2425 + {
1.2426 + TBool threadPassed = ETrue;
1.2427 + TInt threadResult = testThread[i].ExitReason();
1.2428 + if (threadResult != KErrNone)
1.2429 + {
1.2430 + ERR_PRINTF3(_L("Thread %i: Terminated with reason %d"), i, threadResult);
1.2431 + threadPassed = EFalse;
1.2432 + }
1.2433 + TExitCategoryName exitCategory = testThread[i].ExitCategory();
1.2434 + if (exitCategory.Compare(_L("Kill")) != 0)
1.2435 + {
1.2436 + ERR_PRINTF3(_L("Thread %i: Terminated with reason category '%S'"), i, &exitCategory);
1.2437 + threadPassed = EFalse;
1.2438 + }
1.2439 + testThread[i].Close();
1.2440 + numThreadsPassed += (threadPassed) ? 1 : 0;
1.2441 + }
1.2442 + TEST(numThreadsPassed == KNumTestThreads);
1.2443 +
1.2444 + __UHEAP_MARKEND;*/
1.2445 + }
1.2446 +/**
1.2447 +Worker thread for TestMultithreadStressAtlas().
1.2448 +The thread uses RFbsGlyphDataIterator on a CFbsFont of the given TFontSpec.
1.2449 +For each glyph, the image returned by the iterator is compared to the image
1.2450 +returned from CFont::GetCharacterData().
1.2451 +Once complete, the semaphore is signalled to tell the parent process it has
1.2452 +finished.
1.2453 + */
1.2454 +void CleanupFinishSemaphore(TAny* aItem)
1.2455 + {
1.2456 + RSemaphore* semaphore = reinterpret_cast<RSemaphore*>(aItem);
1.2457 + semaphore->Signal();
1.2458 + semaphore->Close();
1.2459 + }
1.2460 +void CTFbsGlyphData::ThreadStressAtlasL(TInt aThreadNum, TGlyphDataMultithreadParams& aParam, CTestStep* aStep)
1.2461 + {
1.2462 + TOpenFontCharMetrics charMetrics;
1.2463 + const TUint8* bitmapData;
1.2464 + TSize bitmapSize;
1.2465 + RSgImage charDataImage;
1.2466 +
1.2467 + RSemaphore threadFinishSemaphore;
1.2468 + User::LeaveIfError(threadFinishSemaphore.OpenGlobal(KTestMultithreadStressFinishSemaphore));
1.2469 + CleanupStack::PushL(TCleanupItem(CleanupFinishSemaphore, &threadFinishSemaphore));
1.2470 +
1.2471 + User::LeaveIfError(RFbsSession::Connect());
1.2472 + CFbsTypefaceStore* ts = CFbsTypefaceStore::NewL(NULL);
1.2473 + CleanupStack::PushL(ts);
1.2474 +
1.2475 + CFbsFont* font;
1.2476 + User::LeaveIfError(ts->GetNearestFontToDesignHeightInPixels((CFont*&)font, aParam.iFontSpec));
1.2477 +
1.2478 + TInt numGlyphMatches = 0;
1.2479 + TInt index = 0;
1.2480 + TInt err = KErrNone;
1.2481 + RFbsGlyphDataIterator iter;
1.2482 + for (err = iter.Open(*font, aParam.iGlyphCodes, aParam.iGlyphCodesCount); err == KErrNone; err = iter.Next(), ++index)
1.2483 + {
1.2484 + TBool glyphMatch = EFalse;
1.2485 + font->GetCharacterData(aParam.iGlyphCodes[index] | KGlyphCodeFlag, charMetrics, bitmapData, bitmapSize);
1.2486 + if (bitmapSize == TSize(0, 0))
1.2487 + {
1.2488 + glyphMatch = (bitmapSize == iter.Rect().Size());
1.2489 + }
1.2490 + else
1.2491 + {
1.2492 + err = CreateSgImageFromCharacterData(bitmapData, bitmapSize, font->FontSpecInTwips().iFontStyle.BitmapType(), charDataImage);
1.2493 + if (err == KErrNone)
1.2494 + {
1.2495 + err = CompareSgImages(aParam.iEGL, iter.Image(), iter.Rect(), charDataImage, TRect(bitmapSize), glyphMatch);
1.2496 + }
1.2497 + charDataImage.Close();
1.2498 + }
1.2499 + if (err != KErrNone)
1.2500 + {
1.2501 + break;
1.2502 + }
1.2503 + numGlyphMatches += (glyphMatch) ? 1 : 0;
1.2504 + }
1.2505 + iter.Close();
1.2506 +
1.2507 + if (index != aParam.iGlyphCodesCount)
1.2508 + {
1.2509 + aStep->ERR_PRINTF5(_L("Thread %d: Iterator terminated early - %d out of %d glyphs (err=%d)"), aThreadNum, index, aParam.iGlyphCodesCount, err);
1.2510 + aStep->SetTestStepResult(EFail);
1.2511 + }
1.2512 + if (index != numGlyphMatches)
1.2513 + {
1.2514 + aStep->ERR_PRINTF4(_L("Thread %d: Matched %d out of %d glyphs"), aThreadNum, numGlyphMatches, aParam.iGlyphCodesCount);
1.2515 + aStep->SetTestStepResult(EFail);
1.2516 + }
1.2517 +
1.2518 + ts->ReleaseFont(font);
1.2519 + CleanupStack::PopAndDestroy(2); // ts, threadFinishSemaphore
1.2520 + RFbsSession::Disconnect();
1.2521 + }
1.2522 +
1.2523 +/**
1.2524 +@SYMTestCaseID GRAPHICS-FBSERV-0673
1.2525 +@SYMTestPriority Medium
1.2526 +@SYMTestType UT
1.2527 +@SYMTestStatus Implemented
1.2528 +@SYMPREQ PREQ2678
1.2529 +
1.2530 +@SYMTestCaseDesc
1.2531 + Tests the robustness of using RFbsGlyphMetricsArray when the client heap and the
1.2532 + FbServ private heap experience failures allocating memory, causing no panics
1.2533 + or leaves.
1.2534 +
1.2535 +@SYMTestActions
1.2536 + i. Set the default heap failure for the next heap allocation.
1.2537 + ii. Create a new CFbsFont using a TFontSpec not already in the glyph atlas.
1.2538 + iii. Call RFbsGlyphMetricsArray::Get(), and close the array.
1.2539 + iv. Release the font so that nothing is left in the cache as a result of
1.2540 + attempting to use it, and reset the heap failure state.
1.2541 + v. While iii returns KErrNoMemory, increment the failure count and repeat
1.2542 + step ii.
1.2543 + vi. Using a separate font so that the test is not affected by the earlier
1.2544 + run, repeat ii. to v., but rather than setting the default heap to
1.2545 + fail, the FbServ private heap is set to fail, via IPC messages to Fbs.
1.2546 +
1.2547 +@SYMTestExpectedResults
1.2548 + If no errors occur, KErrNone should be returned after a certain number of
1.2549 + repetitions. Any other error code denotes a problem handling low-memory
1.2550 + situtations.
1.2551 +*/
1.2552 +void CTFbsGlyphData::TestGlyphMetricsArrayHeapOOML()
1.2553 + {
1.2554 + INFO_PRINTF1(_L("Test RFbsGlyphMetricsArray during heap alloc failure"));
1.2555 + __UHEAP_MARK;
1.2556 +
1.2557 + // Create a font that wont be in the cache already...
1.2558 + TInt rep = 0;
1.2559 + TInt err = KErrNoMemory;
1.2560 + CFbsFont* font = NULL;
1.2561 +
1.2562 + while (err == KErrNoMemory)
1.2563 + {
1.2564 + User::LeaveIfError(iTs->GetNearestFontInPixels((CFont*&)font, GenerateDejaVuFontSpec(10)));
1.2565 + __UHEAP_FAILNEXT(rep);
1.2566 + RFbsGlyphMetricsArray array;
1.2567 + err = array.Get(*font, iGlyphCodesLatin, KNumGlyphCodesLatin);
1.2568 + array.Close();
1.2569 + __UHEAP_RESET;
1.2570 + iTs->ReleaseFont(font);
1.2571 + font = NULL;
1.2572 + ++rep;
1.2573 + }
1.2574 +
1.2575 + TESTE(err == KErrNone, err);
1.2576 + if (err == KErrNone)
1.2577 + {
1.2578 + INFO_PRINTF2(_L("Client Heap OOM : Test passed after rep %d"), rep);
1.2579 + }
1.2580 + else
1.2581 + {
1.2582 + ERR_PRINTF3(_L("Client Heap OOM : Test failed with err=%d, after rep %d"), err, rep);
1.2583 + }
1.2584 +
1.2585 + // Now test when the server-side FbServ heap fails...
1.2586 + rep = 0;
1.2587 + err = KErrNoMemory;
1.2588 +
1.2589 + while (err == KErrNoMemory)
1.2590 + {
1.2591 + User::LeaveIfError(iTs->GetNearestFontInPixels((CFont*&)font, GenerateDejaVuFontSpec(11)));
1.2592 + iFbs->SendCommand(EFbsMessSetHeapFail, RFbsSession::EHeapFailTypeServerMemory, rep);
1.2593 + RFbsGlyphMetricsArray array;
1.2594 + err = array.Get(*font, iGlyphCodesLatin, KNumGlyphCodesLatin);
1.2595 + array.Close();
1.2596 + iFbs->SendCommand(EFbsMessSetHeapReset, RFbsSession::EHeapFailTypeServerMemory);
1.2597 + iTs->ReleaseFont(font);
1.2598 + font = NULL;
1.2599 + ++rep;
1.2600 + }
1.2601 +
1.2602 + TESTE(err == KErrNone, err);
1.2603 + if (err == KErrNone)
1.2604 + {
1.2605 + INFO_PRINTF2(_L("FBServ Heap OOM : Test passed after rep %d"), rep);
1.2606 + }
1.2607 + else
1.2608 + {
1.2609 + ERR_PRINTF3(_L("FBServ Heap OOM : Test failed with err=%d, after rep %d"), err, rep);
1.2610 + }
1.2611 + __UHEAP_MARKEND;
1.2612 + }
1.2613 +
1.2614 +/**
1.2615 +@SYMTestCaseID GRAPHICS-FBSERV-0674
1.2616 +@SYMTestPriority Medium
1.2617 +@SYMTestType UT
1.2618 +@SYMTestStatus Implemented
1.2619 +@SYMPREQ PREQ2678
1.2620 +
1.2621 +@SYMTestCaseDesc
1.2622 + Tests the robustness of using RFbsGlyphDataIterator when the client heap and the
1.2623 + FbServ private heap experience failures allocating memory, causing no panics
1.2624 + or leaves.
1.2625 +
1.2626 +@SYMTestActions
1.2627 + i. Set the default heap failure for the next heap allocation.
1.2628 + ii. Create a new CFbsFont using a TFontSpec not already in the glyph atlas.
1.2629 + iii. Call RFbsGlyphDataIterator::Open(), and close the array.
1.2630 + iv. Release the font so that nothing is left in the cache as a result of
1.2631 + attempting to use it, and reset the heap failure state.
1.2632 + v. While iii returns KErrNoMemory, increment the failure count and repeat
1.2633 + step ii.
1.2634 + vi. Using a separate font so that the test is not affected by the earlier
1.2635 + run, repeat ii. to v., but rather than setting the default heap to
1.2636 + fail, the FbServ private heap is set to fail, via IPC messages to Fbs.
1.2637 +
1.2638 +@SYMTestExpectedResults
1.2639 + If no errors occur, KErrNone should be returned after a certain number of
1.2640 + repetitions. Any other error code denotes a problem handling low-memory
1.2641 + situtations.
1.2642 +*/
1.2643 +void CTFbsGlyphData::TestGlyphDataIteratorHeapOOML()
1.2644 + {
1.2645 + INFO_PRINTF1(_L("Test RFbsGlyphDataIterator during heap alloc failure"));
1.2646 + __UHEAP_MARK;
1.2647 +
1.2648 + // Create a font that wont be in the cache already...
1.2649 + TInt rep = 0;
1.2650 + TInt err = KErrNoMemory;
1.2651 + CFbsFont* font = NULL;
1.2652 +
1.2653 + while (err == KErrNoMemory)
1.2654 + {
1.2655 + User::LeaveIfError(iTs->GetNearestFontInPixels((CFont*&)font, GenerateDejaVuFontSpec(10)));
1.2656 + __UHEAP_FAILNEXT(rep);
1.2657 + RFbsGlyphDataIterator iter;
1.2658 + err = iter.Open(*font, iGlyphCodesLatin, KNumGlyphCodesLatin);
1.2659 + if (err == KErrNone)
1.2660 + {
1.2661 + while (err == KErrNone)
1.2662 + {
1.2663 + err = iter.Next();
1.2664 + }
1.2665 + err = (err == KErrNotFound) ? KErrNone : err;
1.2666 + }
1.2667 + iter.Close();
1.2668 + __UHEAP_RESET;
1.2669 + iTs->ReleaseFont(font);
1.2670 + font = NULL;
1.2671 + ++rep;
1.2672 + }
1.2673 +
1.2674 + TESTE(err == KErrNone, err);
1.2675 + if (err == KErrNone)
1.2676 + {
1.2677 + INFO_PRINTF2(_L("Client Heap OOM : Test passed after rep %d"), rep);
1.2678 + }
1.2679 + else
1.2680 + {
1.2681 + ERR_PRINTF3(_L("Client Heap OOM : Test failed with err=%d, after rep %d"), err, rep);
1.2682 + }
1.2683 +
1.2684 + // Now test when the server-side FbServ heap fails...
1.2685 + rep = 0;
1.2686 + err = KErrNoMemory;
1.2687 +
1.2688 + while (err == KErrNoMemory)
1.2689 + {
1.2690 + User::LeaveIfError(iTs->GetNearestFontInPixels((CFont*&)font, GenerateDejaVuFontSpec(11)));
1.2691 + iFbs->SendCommand(EFbsMessSetHeapFail, RFbsSession::EHeapFailTypeServerMemory, rep);
1.2692 + RFbsGlyphDataIterator iter;
1.2693 + err = iter.Open(*font, iGlyphCodesLatin, KNumGlyphCodesLatin);
1.2694 + if (err == KErrNone)
1.2695 + {
1.2696 + while (err == KErrNone)
1.2697 + {
1.2698 + err = iter.Next();
1.2699 + }
1.2700 + err = (err == KErrNotFound) ? KErrNone : err;
1.2701 + }
1.2702 + iter.Close();
1.2703 + iFbs->SendCommand(EFbsMessSetHeapReset, RFbsSession::EHeapFailTypeServerMemory);
1.2704 + iTs->ReleaseFont(font);
1.2705 + font = NULL;
1.2706 + ++rep;
1.2707 + }
1.2708 +
1.2709 + TESTE(err == KErrNone, err);
1.2710 + if (err == KErrNone)
1.2711 + {
1.2712 + INFO_PRINTF2(_L("FBServ Heap OOM : Test passed after rep %d"), rep);
1.2713 + }
1.2714 + else
1.2715 + {
1.2716 + ERR_PRINTF3(_L("FBServ Heap OOM : Test failed with err=%d, after rep %d"), err, rep);
1.2717 + }
1.2718 + __UHEAP_MARKEND;
1.2719 + }
1.2720 +
1.2721 +/**
1.2722 +Utility function. Prints out a description of the font's fontspec to the log.
1.2723 + */
1.2724 +void CTFbsGlyphData::InfoPrintFontSpec(const CFont& aFont)
1.2725 + {
1.2726 + _LIT(KMonochromeBitmap, "Mono");
1.2727 + _LIT(KAntiAliasedBitmap, "AA");
1.2728 + _LIT(KStyleItalic, "Italic");
1.2729 + _LIT(KStyleBold, "Bold");
1.2730 + _LIT(KStyleNormal, "Normal");
1.2731 + _LIT(KUnknown, "Unknown");
1.2732 + TBufC<9> bitmapType;
1.2733 + TBuf<12> fontStyle;
1.2734 + TFontSpec fontSpec = aFont.FontSpecInTwips();
1.2735 + switch(fontSpec.iFontStyle.BitmapType())
1.2736 + {
1.2737 + case EMonochromeGlyphBitmap:
1.2738 + bitmapType = KMonochromeBitmap;
1.2739 + break;
1.2740 + case EAntiAliasedGlyphBitmap:
1.2741 + bitmapType = KAntiAliasedBitmap;
1.2742 + break;
1.2743 + default:
1.2744 + bitmapType = KUnknown;
1.2745 + }
1.2746 +
1.2747 + if (fontSpec.iFontStyle.StrokeWeight() == EStrokeWeightBold)
1.2748 + {
1.2749 + fontStyle.Append(KStyleBold);
1.2750 + }
1.2751 + if (fontSpec.iFontStyle.Posture() == EPostureItalic)
1.2752 + {
1.2753 + fontStyle.Append(KStyleItalic);
1.2754 + }
1.2755 + if (fontStyle.Length() == 0)
1.2756 + {
1.2757 + fontStyle = KStyleNormal;
1.2758 + }
1.2759 +
1.2760 + INFO_PRINTF5(_L("Font: name=%S size=%dtw type=%S style=%S"), &(fontSpec.iTypeface.iName), fontSpec.iHeight, &bitmapType, &fontStyle);
1.2761 + }
1.2762 +
1.2763 +
1.2764 +/**
1.2765 +Static utility function. Performs a per-pixel comparison of two open RSgImages.
1.2766 +To do this requires access to the binary data of the images, only accessable
1.2767 +via EGL and Khronos APIs. This function will bind the RSgImages to VGImages
1.2768 +and uses OpenVG to retrieve the image data in 8bpp.
1.2769 +@param aEGL An EGL Helper to read the SgImages into system memory.
1.2770 +@param aImageA The first image to compare.
1.2771 +@param aRectA A rectangular portion in pixels of the first image to compare.
1.2772 +@param aImageB The second image to compare.
1.2773 +@param aRectB A rectangular portion in pixels fo the second image to compare.
1.2774 +@param aMatch A boolean value, which on return tells the caller whether the two
1.2775 + images were deemed to match.
1.2776 +@return KErrNone, if the comparison took place, otherwise one of the system-wide
1.2777 + error codes.
1.2778 +*/
1.2779 +TInt CTFbsGlyphData::CompareSgImages(CEGLHelper* aEGL, const RSgImage& aImageA, const TRect& aRectA, const RSgImage& aImageB, const TRect& aRectB, TBool& aMatch)
1.2780 + {
1.2781 + return CTFbsGlyphData::CompareSgImages(aEGL, aImageA, aRectA, NULL, aImageB, aRectB, NULL, aMatch);
1.2782 + }
1.2783 +
1.2784 +/**
1.2785 +Static utility function. Performs a per-pixel comparison of two open RSgImages.
1.2786 +To do this requires access to the binary data of the images, only accessable
1.2787 +via EGL and Khronos APIs. This function will bind the RSgImages to VGImages
1.2788 +and uses OpenVG to retrieve the image data in 8bpp.
1.2789 +This version allows pre-created memory to be used in the comparison, to avoid
1.2790 +allocation failure in low memory testing.
1.2791 +@param aEGL An EGL Helper to read the SgImages into system memory buffers.
1.2792 +@param aImageA The first image to compare.
1.2793 +@param aRectA A rectangular portion in pixels of the first image to compare.
1.2794 +@param aBufferA If non-NULL, specifies a memory buffer to read the data of
1.2795 + aImageA into, otherwise a buffer is dynamically allocated.
1.2796 +@param aImageB The second image to compare.
1.2797 +@param aRectB A rectangular portion in pixels fo the second image to compare.
1.2798 +@param aBufferB If non-NULL, specifies a memory buffer to read the data of
1.2799 + aImageB into, otherwise a buffer is dynamically allocated.
1.2800 +@param aMatch A boolean value, which on return tells the caller whether the two
1.2801 + images were deemed to match.
1.2802 +@return KErrNone, if the comparison took place, otherwise one of the system-wide
1.2803 + error codes.
1.2804 +*/
1.2805 +TInt CTFbsGlyphData::CompareSgImages(CEGLHelper* aEGL, const RSgImage& aImageA, const TRect& aRectA, TUint8* aBufferA, const RSgImage& aImageB, const TRect& aRectB, TUint8* aBufferB, TBool& aMatch)
1.2806 + {
1.2807 + // By default, assume they do not match.
1.2808 + aMatch = EFalse;
1.2809 +
1.2810 +#ifdef SAVEGLYPHSTOMBMDURINGCOMPARISON
1.2811 +
1.2812 + static TInt countToAppend = 0;
1.2813 +
1.2814 + CFbsBitmap* bitmap = NULL;
1.2815 + if (KErrNone == CreateBitmapFromSgImage(aEGL, aImageA, aRectA, bitmap))
1.2816 + {
1.2817 + TBuf<KMaxFileName> buf;
1.2818 + buf.AppendNum( countToAppend );
1.2819 + TPtrC nameAppend( buf );
1.2820 +
1.2821 + SaveBmp(bitmap, &nameAppend, EFalse);
1.2822 + }
1.2823 + delete bitmap;
1.2824 + if (KErrNone == CreateBitmapFromSgImage(aEGL, aImageB, aRectB, bitmap))
1.2825 + {
1.2826 + TBuf<KMaxFileName> buf;
1.2827 + buf.AppendNum( countToAppend );
1.2828 + TPtrC nameAppend( buf );
1.2829 +
1.2830 + SaveBmp(bitmap, &nameAppend, ETrue);
1.2831 + }
1.2832 + delete bitmap;
1.2833 +
1.2834 + countToAppend++;
1.2835 +
1.2836 +#endif // SAVEGLYPHSTOMBMDURINGCOMPARISON
1.2837 +
1.2838 + TSgImageInfo imageInfoA;
1.2839 + TSgImageInfo imageInfoB;
1.2840 + if (aImageA.GetInfo(imageInfoA) != KErrNone ||
1.2841 + aImageB.GetInfo(imageInfoB) != KErrNone)
1.2842 + {
1.2843 + return KErrBadHandle;
1.2844 + }
1.2845 +
1.2846 + // Check the sizes of the images match, and the rects reside on the images.
1.2847 + if (aRectA.Size() != aRectB.Size() ||
1.2848 + !TRect(imageInfoA.iSizeInPixels).Intersects(aRectA) ||
1.2849 + !TRect(imageInfoB.iSizeInPixels).Intersects(aRectB))
1.2850 + {
1.2851 + return KErrNone;
1.2852 + }
1.2853 + const TSize KBufferSize = aRectA.Size();
1.2854 + const TInt KDataStride = KBufferSize.iWidth;
1.2855 +
1.2856 + TBool freeTempBufA = EFalse;
1.2857 + TBool freeTempBufB = EFalse;
1.2858 + if (!aBufferA)
1.2859 + {
1.2860 + aBufferA = (TUint8*) User::AllocZ(KDataStride * KBufferSize.iHeight);
1.2861 + freeTempBufA = ETrue;
1.2862 + }
1.2863 + if (!aBufferA)
1.2864 + {
1.2865 + return KErrNoMemory;
1.2866 + }
1.2867 + TInt err = aEGL->GetSgImageData(aImageA, aRectA, aBufferA);
1.2868 + if (err != KErrNone)
1.2869 + {
1.2870 + if (freeTempBufA)
1.2871 + {
1.2872 + User::Free(aBufferA);
1.2873 + aBufferA = NULL;
1.2874 + }
1.2875 + return err;
1.2876 + }
1.2877 + if (!aBufferB)
1.2878 + {
1.2879 + aBufferB = (TUint8*) User::AllocZ(KDataStride * KBufferSize.iHeight);
1.2880 + freeTempBufB = ETrue;
1.2881 + }
1.2882 + if (!aBufferB)
1.2883 + {
1.2884 + if (freeTempBufA)
1.2885 + {
1.2886 + User::Free(aBufferA);
1.2887 + aBufferA = NULL;
1.2888 + }
1.2889 + return KErrNoMemory;
1.2890 + }
1.2891 + err = aEGL->GetSgImageData(aImageB, aRectB, aBufferB);
1.2892 + if (err != KErrNone)
1.2893 + {
1.2894 + if (freeTempBufA)
1.2895 + {
1.2896 + User::Free(aBufferA);
1.2897 + aBufferA = NULL;
1.2898 + }
1.2899 + if (freeTempBufB)
1.2900 + {
1.2901 + User::Free(aBufferB);
1.2902 + aBufferB = NULL;
1.2903 + }
1.2904 + return err;
1.2905 + }
1.2906 +
1.2907 + // Perform a per-pixel comparison, scanline by scanline.
1.2908 + // The loop will break as soon as a mismatch is detected.
1.2909 + aMatch = ETrue;
1.2910 + for (TInt scanline = 0; (scanline < KBufferSize.iHeight) && aMatch; ++scanline)
1.2911 + {
1.2912 + TUint8* scanlineImageA = aBufferA + (scanline * KDataStride);
1.2913 + TUint8* scanlineImageB = aBufferB + (scanline * KDataStride);
1.2914 + aMatch = (Mem::Compare(scanlineImageA, KBufferSize.iWidth, scanlineImageB, KBufferSize.iWidth) == 0);
1.2915 + }
1.2916 +
1.2917 + if (freeTempBufA)
1.2918 + {
1.2919 + User::Free(aBufferA);
1.2920 + aBufferA = NULL;
1.2921 + }
1.2922 + if (freeTempBufB)
1.2923 + {
1.2924 + User::Free(aBufferB);
1.2925 + aBufferB = NULL;
1.2926 + }
1.2927 +
1.2928 + return KErrNone;
1.2929 + }
1.2930 +
1.2931 +/**
1.2932 +Second thread entry function for multi-threaded tests.
1.2933 +*/
1.2934 +TInt CTFbsGlyphData::ThreadFunction(TAny* aParam)
1.2935 + {
1.2936 + __UHEAP_MARK;
1.2937 + CTrapCleanup* cleanupStack = CTrapCleanup::New();
1.2938 + if (!cleanupStack)
1.2939 + {
1.2940 + return KErrNoMemory;
1.2941 + }
1.2942 +
1.2943 + TGlyphDataThreadInfo* info = static_cast<TGlyphDataThreadInfo*>(aParam);
1.2944 + TRAPD(result,
1.2945 + switch(info->iTest)
1.2946 + {
1.2947 + case EGlyphDataMultiSessionTestShareGlyphs:
1.2948 + CTFbsGlyphData::ThreadShareGlyphsL(info->iThreadNum, info->iParams, info->iStep);
1.2949 + break;
1.2950 + case EGlyphDataMultiSessionTestStressAtlas:
1.2951 + CTFbsGlyphData::ThreadStressAtlasL(info->iThreadNum, info->iParams, info->iStep);
1.2952 + break;
1.2953 + default:
1.2954 + User::Leave(KErrArgument);
1.2955 + }
1.2956 + );
1.2957 +
1.2958 + delete cleanupStack;
1.2959 + __UHEAP_MARKEND;
1.2960 + return result;
1.2961 + }
1.2962 +
1.2963 +
1.2964 +
1.2965 +/*
1.2966 + -----------------------------------------
1.2967 + Static utility Methods used by the tests.
1.2968 + -----------------------------------------
1.2969 +*/
1.2970 +
1.2971 +
1.2972 +
1.2973 +/**
1.2974 +Utility method that fills the RSgImage memory with RSgImages until either KErrNoMemory
1.2975 +or KErrNoGraphicsMemory is returned.
1.2976 +
1.2977 +@param aSize The size of the image used to fill the graphics memory - a form of granularity
1.2978 +@param aImages Returns the array of the images used to fill the graphics memory.
1.2979 +@return KErrNoGraphicsMemory or KErrNoMemory if successful, otherwise one of the system
1.2980 + wide error codes.
1.2981 + */
1.2982 +/*static TInt FillGraphicsMemoryWithImages(const TSize& aSize, RArray<RSgImage>& aImages)
1.2983 + {
1.2984 + TInt err = KErrNone;
1.2985 + while (KErrNone == err)
1.2986 + {
1.2987 + RSgImage sgImage;
1.2988 + err = sgImage.Create(TSgImageInfo(aSize, ESgPixelFormatA_8, ESgUsageBitOpenVgImage));
1.2989 + if (KErrNone == err)
1.2990 + {
1.2991 + err = aImages.Append(sgImage);
1.2992 + }
1.2993 + }
1.2994 + return err;
1.2995 + }*/
1.2996 +
1.2997 +/**
1.2998 +Utility method that fills the RSgImage memory with RSgImages until either KErrNoMemory
1.2999 +or KErrNoGraphicsMemory is returned and then closes one RSgImage to free up some memory.
1.3000 +
1.3001 +@param aSize The size of the image used to fill the graphics memory - a form of granularity
1.3002 +@param aImages Returns the array of the images used to fill the graphics memory.
1.3003 +@return KErrNone if successful, otherwise one of the system wide error codes.
1.3004 + */
1.3005 +/*static TInt NearlyFillGraphicsMemoryWithImages(const TSize& aSize, RArray<RSgImage>& aImages)
1.3006 + {
1.3007 + TInt err = FillGraphicsMemoryWithImages(aSize, aImages);
1.3008 + if (err == KErrNoMemory || err == KErrNoGraphicsMemory)
1.3009 + {
1.3010 + if (aImages.Count() > 0)
1.3011 + {
1.3012 + // Remove an image to free up some memory.
1.3013 + TInt lastIndex = aImages.Count() - 1;
1.3014 + aImages[lastIndex].Close();
1.3015 + aImages.Remove(lastIndex);
1.3016 + }
1.3017 + err = KErrNone;
1.3018 + }
1.3019 + return err;
1.3020 + }*/
1.3021 +
1.3022 +/**
1.3023 +Static utility function. Creates an 8bpp RSgImage from 1bpp or 8bpp character
1.3024 +data, with VGImage usage flag set.
1.3025 +@param aData The character image data. Either in 8bpp or 1bpp RLE format.
1.3026 +@param aSize The size of the character image in pixels.
1.3027 +@param aType The type of glyph - Monochrome or Antialiased.
1.3028 +@param aSgImage A closed image which will be populated with 8bpp image data.
1.3029 +*/
1.3030 +static TInt CreateSgImageFromCharacterData(const TUint8* aData, const TSize& aSize, TGlyphBitmapType aType, RSgImage& aImage)
1.3031 + {
1.3032 + return CreateSgImageFromCharacterData(aData, aSize, aType, aImage, NULL, NULL);
1.3033 + }
1.3034 +
1.3035 +/**
1.3036 +Static utility function. Creates an 8bpp RSgImage from 1bpp or 8bpp character
1.3037 +data, with VGImage usage flag set.
1.3038 +This overload allows the memory for the buffers to be pre-created to avoid
1.3039 +memory allocation failure during low-memory testing.
1.3040 +@param aData The character image data. Either in 8bpp or 1bpp RLE format.
1.3041 +@param aSize The size of the character image in pixels.
1.3042 +@param aType The type of glyph - Monochrome or Antialiased.
1.3043 +@param aSgImage A closed image which will be populated with 8bpp image data.
1.3044 +@param aBuffer1 If non-NULL, used as a memory buffer for reading the decoded
1.3045 + image data into for monochrome images.
1.3046 +@param aBuffer2 If non-NULL, used as a memory buffer for the decoded image
1.3047 + data for monochrome images.
1.3048 +*/
1.3049 +static TInt CreateSgImageFromCharacterData(const TUint8* aData, const TSize& aSize, TGlyphBitmapType aType, RSgImage& aImage, TUint8* aBuffer1, TUint8* aBuffer2)
1.3050 + {
1.3051 + TInt err = KErrNone;
1.3052 + if (aSize == TSize(0, 0))
1.3053 + {
1.3054 + return KErrArgument;
1.3055 + }
1.3056 + TUint8* dataBuf = NULL;
1.3057 + TInt dataStride = 0;
1.3058 + TBool freeDataBuf = EFalse;
1.3059 + if (aType == EAntiAliasedGlyphBitmap)
1.3060 + {
1.3061 + dataBuf = const_cast<TUint8*>(aData);
1.3062 + dataStride = aSize.iWidth;
1.3063 + }
1.3064 + else if (aType == EMonochromeGlyphBitmap)
1.3065 + {
1.3066 + TUint8* binaryData = NULL;
1.3067 + TUint8* tempBuf = NULL;
1.3068 + TInt binaryDataStride = ((aSize.iWidth + 31) / 32) << 2;
1.3069 + TInt binaryDataSize = binaryDataStride * aSize.iHeight;
1.3070 + if (aBuffer1 && User::AllocLen(aBuffer1) >= binaryDataSize)
1.3071 + {
1.3072 + binaryData = aBuffer1;
1.3073 + }
1.3074 + else
1.3075 + {
1.3076 + tempBuf = (TUint8*) User::AllocZ(binaryDataSize);
1.3077 + if (!tempBuf)
1.3078 + {
1.3079 + return KErrNoMemory;
1.3080 + }
1.3081 + binaryData = tempBuf;
1.3082 + }
1.3083 + // Unpack the run length encoded data into 1bpp
1.3084 + DecodeBinaryData(aSize, aData, binaryDataStride, reinterpret_cast<TUint32*&>(binaryData));
1.3085 + dataStride = aSize.iWidth;
1.3086 + TInt byteDataSize = dataStride * aSize.iHeight;
1.3087 + TUint8* byteData = NULL;
1.3088 + // If aByteBuf supplied, use that instead of allocating a new buffer here.
1.3089 + if (aBuffer2 && User::AllocLen(aBuffer2) >= byteDataSize)
1.3090 + {
1.3091 + byteData = aBuffer2;
1.3092 + }
1.3093 + else
1.3094 + {
1.3095 + byteData = (TUint8*) User::AllocZ(byteDataSize);
1.3096 + if (!byteData)
1.3097 + {
1.3098 + User::Free(tempBuf);
1.3099 + return KErrNoMemory;
1.3100 + }
1.3101 + freeDataBuf = ETrue;
1.3102 + }
1.3103 + dataBuf = byteData;
1.3104 + for (TInt scanline = 0; scanline < aSize.iHeight; ++scanline)
1.3105 + {
1.3106 + TUint8* srcByte = binaryData;
1.3107 + for (TInt pixel = 0; pixel < aSize.iWidth; pixel++)
1.3108 + {
1.3109 + *(byteData+pixel) = ((*srcByte & (1 << (pixel % 8))) == 0) ? 0 : 0xFF;
1.3110 + if (((pixel + 1) % 8) == 0) srcByte++;
1.3111 + }
1.3112 + byteData += dataStride;
1.3113 + binaryData += binaryDataStride;
1.3114 + }
1.3115 + User::Free(tempBuf);
1.3116 + }
1.3117 + else
1.3118 + {
1.3119 + return KErrArgument;
1.3120 + }
1.3121 +
1.3122 + // Create RSgImage from CFbsBitmap.
1.3123 + TSgImageInfo sgImageInfo(aSize, ESgPixelFormatA_8, ESgUsageBitOpenVgImage);
1.3124 + err = aImage.Create(sgImageInfo, dataBuf, dataStride);
1.3125 + if (freeDataBuf)
1.3126 + {
1.3127 + User::Free(dataBuf);
1.3128 + }
1.3129 + return err;
1.3130 + }
1.3131 +
1.3132 +
1.3133 +/**
1.3134 +Static utility function, Copies image data line(s) to a destination.
1.3135 +@param aBinaryDataPtr pointer to a destination buffer.
1.3136 +@param aBufferWords Stride of the image.
1.3137 +@param aData Pointer to a source buffer.
1.3138 +@param aBitShift Number of bits, binary data will be shifted.
1.3139 +@param aCharWidth Width of the image.
1.3140 +@param aRepeatCount Number of lines to copy.
1.3141 +*/
1.3142 +static void CopyCharLine(TUint32*& aBinaryDataPtr,TInt aBufferWords,const TUint8* aData,TInt aBitShift,TInt aCharWidth, TInt16 aRepeatCount)
1.3143 + {
1.3144 + aBitShift&=7;
1.3145 + TInt wordstocopy=(aCharWidth+31)>>5;
1.3146 + if(wordstocopy>aBufferWords) wordstocopy=aBufferWords;
1.3147 + TUint32* ptrlimit=aBinaryDataPtr+wordstocopy;
1.3148 + TUint32* dataword=(TUint32*)(TInt(aData)&~3);
1.3149 + aBitShift+=(TInt(aData)-TInt(dataword))<<3;
1.3150 +
1.3151 + TUint32* startBinaryDataPtr = aBinaryDataPtr;
1.3152 + while(aBinaryDataPtr<ptrlimit)
1.3153 + {
1.3154 + *aBinaryDataPtr=*dataword++;
1.3155 + *aBinaryDataPtr>>=aBitShift;
1.3156 + if(aBitShift) *aBinaryDataPtr|=(*dataword<<(32-aBitShift));
1.3157 + aBinaryDataPtr++;
1.3158 + }
1.3159 +
1.3160 + TUint32* curStartBinaryDataPtr = aBinaryDataPtr;
1.3161 + TInt byteToCopy = wordstocopy << 2;
1.3162 + while(aRepeatCount > 1)
1.3163 + {
1.3164 + Mem::Copy(curStartBinaryDataPtr, startBinaryDataPtr, byteToCopy);
1.3165 + curStartBinaryDataPtr += wordstocopy;
1.3166 +
1.3167 + aRepeatCount--;
1.3168 + }
1.3169 + aBinaryDataPtr = curStartBinaryDataPtr;
1.3170 + }
1.3171 +
1.3172 +/**
1.3173 +Static utility function. Decodes a monochrome glyph whose data is run length encoded,
1.3174 +into a 1bpp bitmap.
1.3175 +@param aDataSize Image size in pixels.
1.3176 +@param aData Pointer to a source buffer.
1.3177 +@param aStride Image data stride.
1.3178 +@param aBinaryData Pointer to a destination buffer. This buffer must be allocated
1.3179 + by the caller.
1.3180 +*/
1.3181 +static void DecodeBinaryData(const TSize& aDataSize, const TUint8* aData, TInt aStride,
1.3182 + TUint32* aBinaryData)
1.3183 + {
1.3184 + const TInt datalength = aDataSize.iWidth;
1.3185 + const TInt dataheight = aDataSize.iHeight;
1.3186 + TInt bitindex=0;
1.3187 + TInt16 repeatcount=0;
1.3188 + TUint32* slbuffer=aBinaryData;
1.3189 + const TInt slwords=aStride;
1.3190 +
1.3191 + for(TInt charline=0;charline<dataheight;charline+=repeatcount) // for lines in the character...
1.3192 + {
1.3193 + repeatcount=CFbsBitGc::Load16(aData+(bitindex>>3));
1.3194 + repeatcount>>=bitindex&7;
1.3195 + const TInt multilineflag=repeatcount&1;
1.3196 + repeatcount>>=1;
1.3197 + repeatcount&=0xf;
1.3198 + bitindex+=5;
1.3199 + if(multilineflag)
1.3200 + {
1.3201 + for(TInt currentline=0;currentline<repeatcount;currentline++)
1.3202 + {
1.3203 + CopyCharLine(slbuffer,slwords,aData+(bitindex>>3),bitindex&7,datalength, 1);
1.3204 + bitindex+=datalength;
1.3205 + }
1.3206 + }
1.3207 + else
1.3208 + {
1.3209 + CopyCharLine(slbuffer,slwords,aData+(bitindex>>3),bitindex&7,datalength, repeatcount);
1.3210 + bitindex+=datalength;
1.3211 + }
1.3212 + }
1.3213 + }
1.3214 +//--------------
1.3215 +__CONSTRUCT_STEP__(FbsGlyphData)