os/graphics/fbs/fontandbitmapserver/sfbs/glyphatlas.cpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
     1 // Copyright (c) 2009-2010 Nokia Corporation and/or its subsidiary(-ies).
     2 // All rights reserved.
     3 // This component and the accompanying materials are made available
     4 // under the terms of "Eclipse Public License v1.0"
     5 // which accompanies this distribution, and is available
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 //
    15 
    16 #include "glyphatlas.h"
    17 #include "OstTraceDefinitions.h"
    18 #ifdef OST_TRACE_COMPILER_IN_USE
    19 #include "glyphatlasTraces.h"
    20 #endif
    21 
    22 
    23 extern void Panic(TFbsPanic aPanic);
    24 
    25 static TInt16 Load16(const TUint8* aPtr);
    26 static void DecodeBinaryData(const TSize& aGlyphSize, const TUint8* aEncodedData, TUint8* aByteData);
    27 static void DecodeBinaryDataExLarge(const TSize& aGlyphSize, const TUint8* aEncodedData, TUint8* aByteData);
    28 static void Convert1BppTo8Bpp(TUint32 aSrcData, TUint8*& aDestDataPtr, const TUint8* aDestDataPtrLimit);
    29 static void CopyCharLine(TUint8*& aByteDataPtr, TInt aWidthInBytes, const TUint8* aSrcData, TInt aBitShift, TInt16 aRepeatCount);
    30 
    31 // === CGlyphAtlas Functions ===
    32 
    33 /**
    34 Glyph Atlas constructor.
    35 @param aMaxCacheSizeInBytes The maximum amount of specialised graphics memory 
    36 	that the glyph atlas should use. If this value is KGlyphAtlasNoCacheLimit,
    37 	then there is no limit and the atlas will use as much memory as is available
    38 	in the system.
    39 */
    40 CGlyphAtlas::CGlyphAtlas(TInt aMaxCacheSizeInBytes)
    41 	:iLruPageList(_FOFF(CGlyphAtlasPage, iLink)),
    42 	 iFontEntryArray(32, _FOFF(TFontEntryMap, iFont)),
    43 	 iMaxCacheSizeInBytes(aMaxCacheSizeInBytes),
    44 	 iMaxCacheSizeHigh(aMaxCacheSizeInBytes),
    45 	 iGpuCacheSizeLimitIsMax(ETrue)
    46 	{
    47     iMaxCacheSizeLow = ( KGlyphAtlasNoCacheLimit == aMaxCacheSizeInBytes )
    48                      ? KGlyphAtlasLowMemCacheLimitDefault
    49                      : ( aMaxCacheSizeInBytes / KGlyphAtlasLowMemCacheLimitDivisor );
    50 	}
    51 
    52 /**
    53 Glyph Atlas destructor.
    54 Frees all the RSgImage handles, frees all the allocated system memory, and
    55 closes the Graphics Resource driver. 
    56 */
    57 CGlyphAtlas::~CGlyphAtlas()
    58 	{
    59 	// cycle through all the font entries and destroy them
    60 	for (TInt ii = iFontEntryArray.Count()-1; ii >= 0; --ii)
    61 		{
    62 		DeleteFontEntry(iFontEntryArray[ii].iEntry);
    63 		}
    64 	iFontEntryArray.Close();
    65 	__ASSERT_DEBUG(iLruPageList.IsEmpty(), Panic(EFbsPanicGlyphAtlasInconsistentState));
    66 	
    67 	// there shouldn't be any remaining pages, but if there are, destroy them.
    68 	while (!iLruPageList.IsEmpty())
    69 		{
    70 		delete iLruPageList.First();
    71 		}
    72 	iSgDriver.Close();
    73 	}
    74 
    75 /**
    76 Factory constructor method. Creates a new glyph atlas.
    77 
    78 @param aMaxCacheSizeInBytes The size in bytes, to use as the upper limit
    79 	for the size of memory used by the glyph images in the atlas. If this
    80 	value is KGlyphAtlasNoCacheLimit, then there is no limit and the atlas
    81 	will use as much memory as is available in the system.
    82 
    83 @return A pointer to the newly-constructed atlas
    84 
    85 @leave KErrNoMemory if there was insufficient memory to create the atlas, 
    86 	or a system wide error code if its RSgDriver failed to open.
    87 */
    88 CGlyphAtlas* CGlyphAtlas::NewL(TInt aMaxCacheSizeInBytes)
    89 	{
    90 	CGlyphAtlas* self = new (ELeave) CGlyphAtlas(aMaxCacheSizeInBytes);
    91 	CleanupStack::PushL(self);
    92 	self->ConstructL();
    93 	CleanupStack::Pop(); // self;
    94 	return self;
    95 	}
    96 
    97 /**
    98 Two-phase constructor.
    99 @leave A system wide error code if RSgDriver failed to open.
   100 */
   101 void CGlyphAtlas::ConstructL()
   102 	{
   103 	User::LeaveIfError(iSgDriver.Open());
   104 	}
   105 
   106 /**
   107 Retrieves a glyph from the atlas.
   108 If the glyph is found, the glyph data passed in is populated.
   109 
   110 @param[in] aFont The font the glyph belongs to.
   111 @param[in] aGlyphCode The glyph code for the glyph being requested.
   112 @param[out] aGlyphImageInfo The glyph image information if this function is successful.
   113 @return KErrNone if the glyph is found, KErrNotFound if not. 
   114 */
   115 TInt CGlyphAtlas::GetGlyph(const CBitmapFont& aFont, TUint aGlyphCode, TGlyphImageInfo& aGlyphImageInfo)
   116 	{
   117     OstTraceExt2( TRACE_NORMAL, CGLYPHATLAS_GETGLYPH, "> f=%x; gc=%04x",(TUint)&aFont, aGlyphCode);
   118     
   119 	CGlyphAtlasFontEntry* fontEntry = FindFontEntry(aFont);
   120 	if (!fontEntry)
   121 		{
   122         OstTrace0( TRACE_NORMAL, CGLYPHATLAS_GETGLYPH_END2, "< KErrNotFound");
   123 		return KErrNotFound;
   124 		}
   125 	TInt err = fontEntry->GetGlyph(aGlyphCode, aGlyphImageInfo);
   126 	
   127 	OstTraceExt5( TRACE_NORMAL, CGLYPHATLAS_GETGLYPH_END1, "< id=%08x%08x; w=%u; h=%u; err=%d", 
   128 	        (TUint)I64HIGH(aGlyphImageInfo.iImageId.iId), (TUint)I64LOW(aGlyphImageInfo.iImageId.iId),
   129 	        (TUint)aGlyphImageInfo.iMetrics.Width(), (TUint)aGlyphImageInfo.iMetrics.Height(), (TInt)err);
   130 	
   131 	return err;
   132 	}
   133 
   134 /**
   135 Adds a glyph to the atlas from a bitmap glyph and retrieves the glyph data.
   136 If there is insufficient memory to create a RSgImage, then the least recently 
   137 used pages (and all the glyphs contained within) are removed until there is 
   138 enough memory to continue.
   139 
   140 @param[in] aFont The font the glyph belongs to.
   141 @param[in] aArgs The information needed to create a glyph.
   142 @param[out] aGlyphImageInfo Upon return contains all the glyph image information needed to use the 
   143 		glyph in another process.
   144 @return KErrNone if the glyph was successfully added or other system-wide error.
   145 */
   146 TInt CGlyphAtlas::AddGlyph(const CBitmapFont& aFont, const TAddGlyphArgs& aArgs, TGlyphImageInfo& aGlyphImageInfo)
   147 	{
   148 	OstTraceDefExt5( OST_TRACE_CATEGORY_DEBUG, TRACE_NORMAL, CGLYPHATLAS_ADDGLYPH, "> f=%x; bp=%08x; gc=%04x; w=%u; h=%u", 
   149 	        (TUint)&aFont, (TUint)aArgs.iBitmapPointer, aArgs.iGlyphCode, 
   150 	        aArgs.iMetrics->Width(), aArgs.iMetrics->Height());
   151 	
   152     // Find font entry and create if none found
   153 	CGlyphAtlasFontEntry* fontEntry = FindFontEntry(aFont);
   154 	TBool isNewFont = EFalse;
   155 	if (!fontEntry)
   156 		{
   157 		// Create a new font.
   158 		fontEntry = CreateFontEntry(aFont);
   159 		if (!fontEntry)
   160 			{
   161             OstTraceDef0(OST_TRACE_CATEGORY_DEBUG, TRACE_NORMAL, CGLYPHATLAS_ADDGLYPH_END2, "< KErrNoMemory");
   162 			return KErrNoMemory;
   163 			}
   164 		isNewFont = ETrue;
   165 		}
   166 	TInt glyphSizeInBytes = 0;
   167 	TInt err = fontEntry->AddGlyph(aArgs, aGlyphImageInfo, glyphSizeInBytes);
   168 	if (KErrNone != err)
   169 		{
   170 		if (isNewFont)
   171 			{
   172 			DeleteFontEntry(fontEntry);
   173 			}
   174 		OstTraceDef1(OST_TRACE_CATEGORY_DEBUG, TRACE_NORMAL, CGLYPHATLAS_ADDGLYPH_END3, "< err=%d", err);
   175 		return err;
   176 		}
   177 	iCacheSizeInBytes += glyphSizeInBytes;
   178 
   179 	// If there is a cache limit and it is now exceeded, remove the least
   180 	// recently used pages until the cache size is within the upper limit. Do 
   181 	// not remove the page relating to the glyph which is being added, which is 
   182 	// now at the head of the LRU array.
   183 	if (iMaxCacheSizeInBytes != KGlyphAtlasNoCacheLimit)
   184 		{
   185 		TBool morePagesToDelete = ETrue;
   186 		while ((iCacheSizeInBytes > iMaxCacheSizeInBytes) && morePagesToDelete)
   187 			{
   188 			morePagesToDelete = DeleteLeastRecentlyUsedPage(EFalse);
   189 			}
   190 		}
   191 	
   192 	OstTraceDefExt2(OST_TRACE_CATEGORY_DEBUG, TRACE_NORMAL, CGLYPHATLAS_ADDGLYPH_END1, "< id=%08x%08x", 
   193 	            I64HIGH(aGlyphImageInfo.iImageId.iId), I64LOW(aGlyphImageInfo.iImageId.iId));
   194     
   195 	return KErrNone;
   196 	}
   197 
   198 /**
   199 Releases all glyphs associated with a particular font when it has been
   200 released by the font system.
   201 
   202 @param aFont The font which is released.
   203  */
   204 void CGlyphAtlas::FontReleased(const CBitmapFont& aFont)
   205 	{
   206 	OstTraceDef1(OST_TRACE_CATEGORY_DEBUG, TRACE_NORMAL, CGLYPHATLAS_FONTRELEASED, "> f=%x", (TUint)&aFont);
   207 	
   208     TInt index = iFontEntryArray.FindInUnsignedKeyOrder(TFontEntryMap(&aFont, NULL));
   209 	if (KErrNotFound == index)
   210 		{
   211         OstTraceDef0(OST_TRACE_CATEGORY_DEBUG, TRACE_NORMAL, CGLYPHATLAS_FONTRELEASED_END2, "< KErrNotFound");
   212 		return;
   213 		}
   214 	CGlyphAtlasFontEntry* fontEntry = iFontEntryArray[index].iEntry;
   215 	iCacheSizeInBytes -= fontEntry->SizeInBytes();
   216 	delete fontEntry;
   217 	iFontEntryArray.Remove(index);
   218 	OstTraceDef0(OST_TRACE_CATEGORY_DEBUG, TRACE_NORMAL, CGLYPHATLAS_FONTRELEASED_END3, "< KErrNone");
   219 	}
   220 
   221 /**
   222 Searches the array of font entries to find the entry for the given font.
   223 If the font entry is found, the entry is returned. If not a NULL pointer is 
   224 returned.
   225 
   226 @param aFont The font to match an entry with.
   227 @return The font entry if a match is found, NULL if not. 
   228 */
   229 CGlyphAtlasFontEntry* CGlyphAtlas::FindFontEntry(const CBitmapFont& aFont) const
   230 	{
   231 	TFontEntryMap entryToMatch(&aFont, NULL);
   232 	TInt index = iFontEntryArray.FindInUnsignedKeyOrder(entryToMatch);
   233 	if (KErrNotFound == index)
   234 		{
   235 		return NULL;
   236 		}
   237 	return iFontEntryArray[index].iEntry;
   238 	}
   239 
   240 /**
   241 Deletes the given font entry.
   242 The mapping from the font to the font entry is removed.
   243 
   244 @param aFontEntry The entry to delete.
   245 */
   246 void CGlyphAtlas::DeleteFontEntry(CGlyphAtlasFontEntry* aFontEntry)
   247 	{
   248     __ASSERT_DEBUG(aFontEntry, Panic(EFbsPanicGlyphAtlasInconsistentState));
   249     TInt index = iFontEntryArray.FindInUnsignedKeyOrder(TFontEntryMap(&aFontEntry->Font(), NULL));
   250     __ASSERT_DEBUG(KErrNotFound != index, Panic(EFbsPanicGlyphAtlasInconsistentState));
   251     if (KErrNotFound != index)
   252         {
   253         iFontEntryArray.Remove(index);
   254         }
   255     iCacheSizeInBytes -= aFontEntry->SizeInBytes();
   256     delete aFontEntry;
   257 	}
   258 
   259 /**
   260 Moves the given page to the front (the position of the most recently used page) 
   261 of the usage order list.
   262 
   263 @param aPage The most recently used page.
   264 */
   265 void CGlyphAtlas::MovePageToFront(CGlyphAtlasPage& aPage)
   266 	{
   267 	aPage.MoveToFirstInQueue(iLruPageList);
   268 	}
   269 
   270 /**
   271 Creates a font entry from the given font and adds a mapping from the font 
   272 to the font entry.
   273 If successful, the font entry is returned.
   274 If either the creation of the font entry or the adding the mapping fails, then 
   275 a NULL pointer is returned.
   276 
   277 @param aFont The font used to create a font entry from.
   278 @return A new font entry if successful, NULL if not.
   279 */
   280 CGlyphAtlasFontEntry* CGlyphAtlas::CreateFontEntry(const CBitmapFont& aFont)
   281 	{
   282 	CGlyphAtlasFontEntry* fontEntry = new CGlyphAtlasFontEntry(aFont, *this);
   283 	if (!fontEntry)
   284 		{
   285 		return NULL;
   286 		}
   287 	// Add font entry to font entry array
   288 	TFontEntryMap fontEntryMap(&aFont, fontEntry);
   289 	TInt err = iFontEntryArray.InsertInUnsignedKeyOrder(fontEntryMap);
   290 	__ASSERT_DEBUG(KErrAlreadyExists != err, Panic(EFbsPanicGlyphAtlasInconsistentState));
   291 	if (KErrNone != err)
   292 		{
   293 		delete fontEntry;
   294 		fontEntry = NULL;
   295 		}
   296 	return fontEntry;
   297 	}
   298 
   299 /**
   300 Deletes the least recently used page and removes it from the list of pages
   301 held by the atlas.
   302 
   303 @param aAllowMruPageDeletion ETrue if the most recently used page can be deleted, 
   304 	EFalse otherwise.
   305 @return ETrue, if there are pages remaining in the atlas after the deletion, EFalse
   306 	otherwise. If there is only one page in the atlas and aAllowMruPageDeletion is EFalse,
   307 	EFalse is returned. 
   308 */
   309 TBool CGlyphAtlas::DeleteLeastRecentlyUsedPage(TBool aAllowMruPageDeletion)
   310 	{
   311     OstTraceDef1(OST_TRACE_CATEGORY_DEBUG, TRACE_NORMAL, CGLYPHATLAS_DELETELEASTRECENTLYUSEDPAGE, "> mru=%d", aAllowMruPageDeletion );
   312     
   313 	CGlyphAtlasPage* lruPage = NULL;
   314 	if (!iLruPageList.IsEmpty())
   315 		{
   316 		lruPage = iLruPageList.Last();
   317 		if (!aAllowMruPageDeletion && (lruPage == iLruPageList.First()))
   318 			{
   319 			lruPage = NULL;
   320 			}
   321 		}
   322 	TBool canDeleteMorePages = EFalse;
   323 	if (lruPage)
   324 		{
   325 		iCacheSizeInBytes -= lruPage->SizeInBytes();
   326 		CGlyphAtlasFontEntry& fontEntry = lruPage->FontEntry();
   327 		fontEntry.DeletePage(lruPage);
   328 		lruPage = NULL;
   329 		if (fontEntry.IsEmpty())
   330 			{
   331 			DeleteFontEntry(&fontEntry);
   332 			}
   333 		canDeleteMorePages = !iLruPageList.IsEmpty();
   334 		}
   335 	OstTraceDefExt2(OST_TRACE_CATEGORY_DEBUG, TRACE_NORMAL, CGLYPHATLAS_DELETELEASTRECENTLYUSEDPAGE_END, "< more=%u; size=%u", (TUint)canDeleteMorePages, iCacheSizeInBytes);
   336 	return canDeleteMorePages;
   337 	}
   338 
   339 /**
   340 Utility function that calculates the number of unique fonts associated with the atlas.
   341 @return Number of fonts in the atlas.
   342  */
   343 TInt CGlyphAtlas::FontCount() const
   344 	{
   345 	return iFontEntryArray.Count();
   346 	}
   347 
   348 /**
   349 Utility function that calculates the number of glyphs across all fonts stored in
   350 the atlas.
   351 @return Number of glyphs in the atlas.
   352  */
   353 TInt CGlyphAtlas::GlyphCount() const
   354 	{
   355 	TInt glyphCount = 0;
   356 	for (TInt ii = iFontEntryArray.Count() - 1; ii >= 0; --ii)
   357 		{
   358 		glyphCount += iFontEntryArray[ii].iEntry->GlyphCount();
   359 		}
   360 	return glyphCount;
   361 	}
   362 
   363 /**
   364 Utility function that calculates the number of glyphs for a given font in the atlas.
   365 @param The font to return the number of glyphs for.
   366 @return Number of glyphs in the atlas.
   367  */
   368 TInt CGlyphAtlas::GlyphCount(const CBitmapFont& aFont) const
   369 	{
   370 	CGlyphAtlasFontEntry* fontEntry = FindFontEntry(aFont);
   371 	return (fontEntry) ? fontEntry->GlyphCount() : 0;
   372 	}
   373 
   374 void CGlyphAtlas::GetGlyphCacheMetrics( TGlyphCacheMetrics& aGlyphCacheMetrics )
   375     {
   376     aGlyphCacheMetrics.iMaxCacheSizeInBytes = iMaxCacheSizeInBytes;
   377     aGlyphCacheMetrics.iMaxCacheSizeHigh = iMaxCacheSizeHigh;
   378     aGlyphCacheMetrics.iMaxCacheSizeLow = iMaxCacheSizeLow;
   379     aGlyphCacheMetrics.iCacheSizeInBytes = iCacheSizeInBytes;
   380     aGlyphCacheMetrics.iGpuCacheSizeLimitIsMax = iGpuCacheSizeLimitIsMax;
   381     }
   382 
   383 /**
   384  Function to release the GPU cache. Called in response to the GoomMonitor's
   385  requirement to reduce GPU memory use.
   386 
   387  @param aBytes. The amount of memory the GOoM framework would like us to relinquish.
   388  @param aFlags. The flags conveyed from the GOoM monitor framework.
   389 */
   390 void CGlyphAtlas::ReleaseGpuMemory( TInt /*aBytes*/, TInt /*aFlags*/ )
   391     {
   392     OstTraceDefExt2( OST_TRACE_CATEGORY_DEBUG, TRACE_NORMAL, CGLYPHATLAS_RELEASEGPUMEMORY, "> max=%d; size=%d", iMaxCacheSizeInBytes, iCacheSizeInBytes);
   393 
   394     if ( iCacheSizeInBytes > 0 )
   395         {
   396         while( DeleteLeastRecentlyUsedPage(ETrue) )
   397             {
   398             // Do nothing
   399             }
   400         }
   401 
   402     // If appropriate, reduce the cache-size limit.
   403     if ( GpuCacheSizeLimitIsMax() )
   404         {
   405         SwitchGpuCacheSizeLimit();
   406         }
   407 
   408     OstTraceDefExt2( OST_TRACE_CATEGORY_DEBUG, TRACE_NORMAL, CGLYPHATLAS_RELEASEGPUMEMORY_EXIT, "< max=%d; size=%d", iMaxCacheSizeInBytes, iCacheSizeInBytes);
   409     }
   410 
   411 /**
   412  Function to establish GPU memory use. Called in response to the GoomMonitor's
   413  notification that GPU memory may once more be utilised in the usual manner.
   414 
   415  @param aFlags. The flags conveyed from the GOoM monitor framework.
   416  */
   417 void CGlyphAtlas::InstateGpuMemory( TInt /*aFlags*/ )
   418     {
   419     OstTraceDef1(OST_TRACE_CATEGORY_DEBUG, TRACE_NORMAL, CGLYPHATLAS_INSTATEGPUMEMORY, "> max=%d", iMaxCacheSizeInBytes );
   420 
   421     // If appropriate, reinstate the full cache-size limit.
   422     if ( !GpuCacheSizeLimitIsMax() )
   423         {
   424         SwitchGpuCacheSizeLimit();
   425         }
   426 
   427     OstTraceDef1(OST_TRACE_CATEGORY_DEBUG, TRACE_NORMAL, CGLYPHATLAS_INSTATEGPUMEMORY_EXIT, "< max=%d", iMaxCacheSizeInBytes );
   428     }
   429 
   430 /**
   431  Utility function to toggle between full and reduced GPU cache-size limits.
   432 
   433  Use in conjunction with TBool GpuCacheSizeLimitIsMax()
   434  */
   435 void CGlyphAtlas::SwitchGpuCacheSizeLimit()
   436     {
   437     if ( GpuCacheSizeLimitIsMax() )
   438         {
   439         // The short-circuit operator obviates tautological conditionals.
   440         while ( (iCacheSizeInBytes >= iMaxCacheSizeLow) && DeleteLeastRecentlyUsedPage(ETrue) )
   441             {
   442             // Do Nothing...
   443             }
   444 
   445         iMaxCacheSizeInBytes = iMaxCacheSizeLow;
   446         iGpuCacheSizeLimitIsMax = EFalse;
   447         }
   448     else
   449         {
   450         iMaxCacheSizeInBytes = iMaxCacheSizeHigh;
   451         iGpuCacheSizeLimitIsMax = ETrue;
   452         }
   453     }
   454 
   455 
   456 /**
   457  Utility function to report whether the GPU cache-size limit is set to the maximum permissible
   458  level, or to its reduced level.
   459 
   460  @return ETrue if the cache-size is set to the maximum permissible limit.
   461          EFalse if it is set to the reduced limit.
   462  */
   463 TBool CGlyphAtlas::GpuCacheSizeLimitIsMax() const
   464     {
   465     return iGpuCacheSizeLimitIsMax;
   466     }
   467 
   468 // === CGlyphAtlasFontEntry Functions ===
   469 /**
   470 Font entry constructor.
   471 
   472 @param aFont The font to which this font entry should be associated.
   473 @param aGlyphAtlas The glyph atlas to which this font entry belongs.
   474 */
   475 CGlyphAtlasFontEntry::CGlyphAtlasFontEntry(const CBitmapFont& aFont, CGlyphAtlas& aGlyphAtlas)
   476 	:iFont(aFont),
   477 	 iPageArray(32, _FOFF(TPageMap, iGlyphCode)),
   478 	 iAtlas(aGlyphAtlas)
   479 	{
   480 	}
   481 
   482 /**
   483 Font entry destructor.
   484 Destroys the pages owned by the font entry.
   485 */
   486 CGlyphAtlasFontEntry::~CGlyphAtlasFontEntry()
   487 	{
   488 	// cycle through all the font entries and destroy them
   489 	for (TInt ii = iPageArray.Count()-1; ii >= 0; --ii)
   490 		{
   491 		DeletePage(iPageArray[ii].iPage);
   492 		}
   493 	__ASSERT_DEBUG(iSizeInBytes == 0, Panic(EFbsPanicGlyphAtlasInconsistentState));
   494 	iPageArray.Close();
   495 	}
   496 
   497 /**
   498 Deletes the given page.
   499 The page mapping is removed and the page is deleted.
   500 
   501 @param aPage The page to delete.
   502 */
   503 void CGlyphAtlasFontEntry::DeletePage(CGlyphAtlasPage* aPage)
   504 	{
   505     __ASSERT_DEBUG(aPage, Panic(EFbsPanicGlyphAtlasInconsistentState));
   506     __ASSERT_DEBUG(iPageArray.Count() > 0, Panic(EFbsPanicGlyphAtlasInconsistentState));
   507 		
   508     TInt numGlyphsInPage = aPage->GlyphCount();
   509 
   510     for (TInt ii = 0; ii < numGlyphsInPage; ++ii)
   511         {
   512         TInt index = iPageArray.FindInUnsignedKeyOrder(TPageMap(aPage->GlyphCodeAt(ii), NULL));
   513 
   514         __ASSERT_DEBUG(KErrNotFound != index, Panic(EFbsPanicGlyphAtlasInconsistentState));
   515 
   516         if (KErrNotFound != index)
   517             {
   518             iPageArray.Remove(index);
   519             iPageArray.GranularCompress();
   520             }
   521         }
   522     iSizeInBytes -= aPage->SizeInBytes();
   523     delete aPage;
   524 
   525 	}
   526 
   527 /**
   528 Adds a glyph to the font from a bitmap glyph and gets the glyph image info back.
   529 
   530 @param[in] aArgs The information needed to create a glyph.
   531 @param[out] aGlyphImageInfo Upon return contains all the glyph image information needed to use the 
   532 		glyph in another process.
   533 @param[out] aSizeInBytes Upon return contains the size of the added glyph's image data in bytes.
   534 @return KErrNone if the glyph was successfully added or other system-wide error.
   535 */
   536 TInt CGlyphAtlasFontEntry::AddGlyph(const CGlyphAtlas::TAddGlyphArgs& aArgs, TGlyphImageInfo& aGlyphImageInfo, TInt& aSizeInBytes)
   537 	{
   538     CGlyphAtlasPage* newPage = new CGlyphAtlasPage(*this);
   539 	if (!newPage)
   540 		{
   541 		return KErrNoMemory;
   542 		}
   543 	
   544 	TInt err = newPage->AddGlyph(aArgs, aGlyphImageInfo, aSizeInBytes);
   545 	if (KErrNone != err)
   546 		{
   547 		delete newPage;
   548 		return err;
   549 		}
   550 
   551 	err = iPageArray.InsertInUnsignedKeyOrder(TPageMap(aArgs.iGlyphCode, newPage));
   552 	__ASSERT_DEBUG(KErrAlreadyExists != err, Panic(EFbsPanicGlyphAtlasInconsistentState));
   553 	if (KErrNone != err)
   554 		{
   555 		delete newPage;
   556 		return err;
   557 		}
   558 	iSizeInBytes += aSizeInBytes;
   559 	iAtlas.MovePageToFront(*newPage);
   560 	return err;
   561 	}
   562 
   563 /**
   564 Searches the array of pages to find the page containing the given glyph.
   565 If the page is found, the glyph image info is populated and the page is moved 
   566 to the front of the Glyph Atlas' LRU page array.
   567 
   568 @param[in] aGlyphCode The glyph code for the glyph being requested.
   569 @param[out] aGlyphImageInfo Upon return contains all the glyph image information needed to use the 
   570 		glyph in another process.
   571 @return KErrNone if the glyph was found, KErrNotFound if not. 
   572 */
   573 TInt CGlyphAtlasFontEntry::GetGlyph(TUint aGlyphCode, TGlyphImageInfo& aGlyphImageInfo)
   574 	{
   575 	TInt index = iPageArray.FindInUnsignedKeyOrder(TPageMap(aGlyphCode, NULL));
   576 	if (KErrNotFound == index)
   577 		{
   578 		return KErrNotFound;
   579 		}
   580 	CGlyphAtlasPage* page = iPageArray[index].iPage;
   581 	page->GetGlyph(aGlyphCode, aGlyphImageInfo);
   582 	iAtlas.MovePageToFront(*page);
   583 	return KErrNone;
   584 	}
   585 
   586 /**
   587 Gets the font associated with the font entry.
   588 
   589 @return The font associated with this entry. 
   590 */
   591 const CBitmapFont& CGlyphAtlasFontEntry::Font() const
   592 	{
   593 	return iFont;
   594 	}
   595 
   596 /**
   597 Gets the amount of memory allocated for all the image data for this font.
   598 
   599 @return The size of the font's image data in bytes.
   600 */
   601 TInt CGlyphAtlasFontEntry::SizeInBytes() const
   602 	{
   603 	return iSizeInBytes;
   604 	}
   605 
   606 /**
   607 Tests whether the font entry has any pages.
   608 
   609 @return ETrue if the font entry does not contain any pages, EFalse if it does..
   610 */
   611 TBool CGlyphAtlasFontEntry::IsEmpty() const
   612 	{
   613 	if (iPageArray.Count() == 0)
   614 		{
   615 		__ASSERT_DEBUG(iSizeInBytes == 0, Panic(EFbsPanicGlyphAtlasInconsistentState));
   616 		return ETrue;
   617 		}
   618 	return EFalse;
   619 	}
   620 
   621 /**
   622 Gets the glyph atlas the font entry belongs to.
   623 
   624 @return The font entry's glyph atlas.
   625 */
   626 CGlyphAtlas& CGlyphAtlasFontEntry::GlyphAtlas() const
   627 	{
   628 	return iAtlas;
   629 	}
   630 
   631 /** 
   632 @return The number of glyphs this font entry has.
   633  */
   634 TInt CGlyphAtlasFontEntry::GlyphCount() const
   635 	{
   636 	TInt glyphCount = 0;
   637 	for (TInt ii = iPageArray.Count() - 1; ii >= 0; --ii)
   638 		{
   639 		glyphCount += iPageArray[ii].iPage->GlyphCount();
   640 		}
   641 	return glyphCount;
   642 	}
   643 
   644 
   645 // === CGlyphAtlasPage Functions ===
   646 
   647 /**
   648 Page constructor.
   649 
   650 @param aFontEntry The font entry to which the page is associated.
   651 */
   652 CGlyphAtlasPage::CGlyphAtlasPage(CGlyphAtlasFontEntry& aFontEntry)
   653 	:iFontEntry(aFontEntry)
   654 	{
   655 	}
   656 
   657 /**
   658 Page destructor.
   659 Releases the RSgImage handles held by the page.
   660 Removes the page from the Glyph Atlas' LRU page array. 
   661 */
   662 CGlyphAtlasPage::~CGlyphAtlasPage()
   663 	{
   664 	iLink.Deque();
   665 	iGlyphImage.Close();
   666 	}
   667 
   668 /**
   669 Adds a glyph to the page from a bitmap glyph and gets the glyph image info back.
   670 An RSgImage handle is acquired for the glyph. 
   671 If there is not enough specialised graphics memory to create a RSgImage, then the
   672 least recently used pages are deleted until there there is either enough memory 
   673 for the creation to be successful or if there are no more pages to delete (in 
   674 which case an appropriate out of memory error message is returned). 
   675 
   676 @param[in] aArgs The information needed to create a glyph.
   677 @param[out] aGlyphImageInfo Upon return contains all the glyph image information needed to use the 
   678 		glyph in another process.
   679 @param[out] aSizeInBytes Upon return contains the size of the added glyph's image data in bytes.
   680 @return KErrNone if the glyph was successfully added; 
   681 	KErrNoMemory if there is not enough system memory available;
   682 	KErrNoGraphicsMemory if there is not enough specialised graphics memory available.
   683 */
   684 TInt CGlyphAtlasPage::AddGlyph(const CGlyphAtlas::TAddGlyphArgs& aArgs, TGlyphImageInfo& aGlyphImageInfo, TInt& aSizeInBytes)
   685 	{
   686 	const TSize glyphSize(aArgs.iMetrics->Width(), aArgs.iMetrics->Height());
   687 	// If glyph has zero size (e.g. space), set glyph data and return 
   688 	if (glyphSize.iWidth == 0 || glyphSize.iHeight == 0)
   689 		{
   690 		iPosX = 0;
   691 		iPosY = 0;
   692 		iMetrics = *aArgs.iMetrics;
   693 		iGlyphCode = aArgs.iGlyphCode;
   694 		iSizeInBytes = 0;
   695 		iNumGlyphs++;
   696 		aGlyphImageInfo.iImageId = KSgNullDrawableId;
   697 		aGlyphImageInfo.iPosX = iPosX;
   698 		aGlyphImageInfo.iPosY = iPosY;
   699 		aGlyphImageInfo.iMetrics = iMetrics;
   700 		return KErrNone;
   701 		}
   702 	TUint8* buf = NULL;
   703 	TSgImageInfo info;
   704 	info.iSizeInPixels = glyphSize;
   705 	info.iUsage = ESgUsageBitOpenVgImage;
   706 	info.iPixelFormat = EUidPixelFormatA_8;
   707 	TInt dataStride = 0;
   708 	const TInt KDataArraySize = 256;
   709 	TUint8 byteDataArray[KDataArraySize];
   710 	TUint8* tempBuf = NULL;
   711 	TUint8* byteDataBuf = NULL;
   712 	TGlyphBitmapType glyphBitmapType = iFontEntry.Font().GlyphBitmapType(); 
   713 
   714 	switch (glyphBitmapType)
   715 		{
   716 		case EMonochromeGlyphBitmap:
   717 			// Decompress to 8bpp buffer
   718 			dataStride = glyphSize.iWidth;
   719 			byteDataBuf = byteDataArray;
   720 			// If data too big to fit in byteDataArray, allocate memory on the heap
   721 			if (glyphSize.iHeight * glyphSize.iWidth > KDataArraySize)
   722 				{
   723 				tempBuf = (TUint8*) User::AllocZ(dataStride * glyphSize.iHeight);
   724 				if (!tempBuf)
   725 					{
   726 					return KErrNoMemory;
   727 					}
   728 				byteDataBuf = tempBuf;
   729 				}
   730 			else
   731 				{
   732 				// fill array with zeros.
   733 				Mem::FillZ(&byteDataArray, KDataArraySize);
   734 				}
   735 			
   736 			if (glyphSize.iWidth >32)
   737 				{
   738 				DecodeBinaryDataExLarge(glyphSize, aArgs.iBitmapPointer, byteDataBuf);
   739 				}
   740 			else
   741 				{
   742 				DecodeBinaryData(glyphSize, aArgs.iBitmapPointer, byteDataBuf);
   743 				}
   744 			buf = byteDataBuf;
   745 			break;
   746 		case EAntiAliasedGlyphBitmap:
   747 			buf = const_cast<TUint8*>(aArgs.iBitmapPointer);
   748 			dataStride = glyphSize.iWidth;
   749 			break;
   750 		default:
   751 			return KErrNotSupported;
   752 		}
   753 
   754 	TInt err = iGlyphImage.Create(info, buf, dataStride);
   755 
   756 	// If RSgImage creation fails due to out of memory, delete the least
   757 	// recently used pages to free up memory until either creation succeeds or 
   758 	// there are no more pages to remove.
   759 	TBool morePagesToDelete = ETrue;
   760 	while ((KErrNoGraphicsMemory == err || KErrNoMemory == err) && morePagesToDelete)
   761 		{
   762 		// Delete least used page.  Can delete all pages if necessary as this  
   763 		// page has not been added to the LRU array yet.
   764 		morePagesToDelete = iFontEntry.GlyphAtlas().DeleteLeastRecentlyUsedPage(ETrue);
   765 		err = iGlyphImage.Create(info, buf, dataStride);
   766 		}
   767 
   768 	User::Free(tempBuf);
   769 	
   770 	if (KErrNone != err)
   771 		{
   772 		return err;
   773 		}
   774 	aSizeInBytes = glyphSize.iHeight * glyphSize.iWidth;
   775 	iGlyphCode = aArgs.iGlyphCode;
   776 	iPosX = 0;
   777 	iPosY = 0;
   778 	iMetrics = *aArgs.iMetrics;
   779 	// As the image is stored as one byte per pixel, the size in bytes is 
   780 	// just the number of pixels.
   781 	// TODO: Replace estimating size with call to SgImage/SgDriver to get accurate size.
   782 	iSizeInBytes += aSizeInBytes;
   783 	iNumGlyphs++;
   784 	aGlyphImageInfo.iPosX = iPosX;
   785 	aGlyphImageInfo.iPosY = iPosY;
   786 	aGlyphImageInfo.iImageId = iGlyphImage.Id();
   787 	aGlyphImageInfo.iMetrics = iMetrics;
   788 	return err;
   789 	}
   790 
   791 /**
   792 Retrieves the glyph image information for the given glyph code necessary to be 
   793 able to use the glyph in another process.
   794 
   795 @param aGlyphCode The glyph code for the glyph being requested
   796 @param aGlyphImageInfo Upon return contains all the glyph image information needed to use the 
   797 		glyph in another process if the glyph is contained in the page.
   798 */
   799 void CGlyphAtlasPage::GetGlyph(TUint aGlyphCode, TGlyphImageInfo& aGlyphImageInfo) const
   800 	{
   801 	__ASSERT_DEBUG(iGlyphCode == aGlyphCode, Panic(EFbsPanicGlyphAtlasInconsistentState));
   802 	aGlyphImageInfo.iMetrics = iMetrics;
   803 	aGlyphImageInfo.iPosX = iPosX;
   804 	aGlyphImageInfo.iPosY = iPosY;
   805 	aGlyphImageInfo.iImageId = iGlyphImage.Id();
   806 	}
   807 
   808 /**
   809 Gets the amount of memory allocated for the image data for this page.
   810 
   811 @return The size of the page's image data in bytes.
   812 */
   813 TInt CGlyphAtlasPage::SizeInBytes() const
   814 	{
   815 	return iSizeInBytes;
   816 	}
   817 
   818 /**
   819 Gets the glyph code at the given index associated with the page.
   820 
   821 @param aIndex The index of the glyph code within the page.
   822 @return The glyph code at the given index.
   823 */
   824 TUint CGlyphAtlasPage::GlyphCodeAt(TInt aIndex) const
   825 	{
   826 	__ASSERT_DEBUG(0 == aIndex, Panic(EFbsPanicGlyphAtlasInconsistentState));
   827 	return iGlyphCode;
   828 	}
   829 
   830 /**
   831 Gets the number of glyphs stored in the page.
   832 
   833 @return The number of glyphs in the page.
   834 */
   835 TInt CGlyphAtlasPage::GlyphCount() const
   836 	{
   837 	return iNumGlyphs;
   838 	}
   839 
   840 /**
   841 Gets the font entry which owns the page.
   842 
   843 @return The font entry which owns the page. 
   844 */
   845 CGlyphAtlasFontEntry& CGlyphAtlasPage::FontEntry() const
   846 	{
   847 	return iFontEntry;
   848 	}
   849 
   850 
   851 void CGlyphAtlasPage::MoveToFirstInQueue(TDblQue<CGlyphAtlasPage>& aList)
   852 	{
   853 	if(!aList.IsFirst(this))
   854 		{
   855 		iLink.Deque();
   856 		aList.AddFirst(*this);
   857 		}
   858 	}
   859 
   860 // === Static Utility Functions ===
   861 
   862 /**
   863 Combines 2 8-bit unsigned integers into a 16-bit integer.
   864 @param aPtr A pointer to a source buffer of 2 8-bit unsigned integers.
   865 @return The two 8-bit integers combined into a 16-bit integer.
   866 */
   867 static TInt16 Load16(const TUint8* aPtr)
   868 	{
   869 	return TInt16(aPtr[0]+(aPtr[1]<<8)); 
   870 	}
   871 
   872 /**
   873 Decodes binary data for monochrome glyph bitmap.
   874 
   875 @param aGlyphSize size of glyph in pixels.
   876 @param aEncodedData Pointer to an encoded source buffer.
   877 @param aByteData Pointer to a destination buffer (8 bits per pixel).
   878 */
   879 void DecodeBinaryData(const TSize& aGlyphSize, const TUint8* aEncodedData, TUint8* aByteData)
   880 	{
   881 	const TInt dataHeight = aGlyphSize.iHeight;
   882 	const TInt dataWidth = aGlyphSize.iWidth;
   883 	TUint32 binaryData = 0;
   884 	
   885 	// The data is encoded as follows:
   886 	// 1 bit for a multiple lines flag (1=yes)
   887 	// 4 bits for a repeat count which represents:
   888 	// -if the multiple line flag is 0 the number of lines whose data is repeated
   889 	// -if the flag is 1, the number of lines which differ from line to line.
   890 	// n bits representing the data at 1 bit per pixel, where:
   891 	// -if the multiple line flag is 0, n is the width of the glyph.
   892 	// -if the flag is 1, n is width of glyph multiplied by the repeat count for this block of data.
   893 	// This information presented in continuous packed blocks of:
   894 	// [data][reps][multiLineFlag]
   895 	TInt bitIndex = 0;
   896 	TInt16 repeatCount = 0;
   897 	TUint8* byteDataPtr = aByteData;
   898 	TUint8* byteDataPtrLimit = NULL;
   899 	for (TInt charLine = 0; charLine < dataHeight; charLine += repeatCount) // for lines in the character...
   900 		{
   901 		// Get first 5 bits of block
   902 		repeatCount = Load16(aEncodedData + (bitIndex >> 3));
   903 		repeatCount >>= bitIndex & 7;
   904 		// strip out multiple line flag (1st bit)
   905 		TInt multiLineFlag = repeatCount & 1;
   906 		// Get repeat count (last 4 bits)
   907 		repeatCount >>= 1;
   908 		repeatCount &= 0xf;
   909 		// move bit index to point to first bit of image data
   910 		bitIndex += 5;
   911 		// end pointer of destination buffer for this block of data to fill 
   912 		byteDataPtrLimit = aByteData + dataWidth * (charLine + repeatCount);
   913 		if (multiLineFlag)
   914 			{
   915 			while (byteDataPtr < byteDataPtrLimit)
   916 				{
   917 				// Pointer to beginning of data in source buffer for current scanline
   918 				TInt charDataOffsetPtr = TInt(aEncodedData) + (bitIndex >> 3);
   919 				// Pointer to beginning of current word.
   920 				TUint32* charDataWord = (TUint32*)(charDataOffsetPtr &~ 3);
   921 				// Number of bits to shift in current word to get to beginning of scanline
   922 				TInt bitShift = bitIndex & 7;
   923 				bitShift += (charDataOffsetPtr & 3) << 3;
   924 				// Copy scanline data into temporary buffer
   925 				binaryData = (*charDataWord++) >> bitShift;
   926 				// If data crosses a word boundary, get the rest of the data from next word.
   927 				if (bitShift)
   928 					{
   929 					binaryData |= (*charDataWord << (32-bitShift));
   930 					}
   931 				Convert1BppTo8Bpp(binaryData, byteDataPtr, byteDataPtr + dataWidth);
   932 				// Move bit index to beginning of next block
   933 				bitIndex += dataWidth;
   934 				}
   935 			}
   936 		else
   937 			{
   938 			TInt charDataOffsetPtr = TInt(aEncodedData) + (bitIndex >> 3);
   939 			TUint32* charDataWord = (TUint32*)(charDataOffsetPtr &~ 3);
   940 			TInt bitShift = bitIndex & 7;
   941 			bitShift += (charDataOffsetPtr & 3) << 3;
   942 			binaryData = (*charDataWord++) >> bitShift;
   943 			if (bitShift)
   944 				{
   945 				binaryData |= (*charDataWord << (32-bitShift));
   946 				}
   947 			TUint8* startByteDataPtr = byteDataPtr;
   948 			Convert1BppTo8Bpp(binaryData, byteDataPtr, byteDataPtr + dataWidth);
   949 			
   950 			while (byteDataPtr < byteDataPtrLimit)
   951 				{
   952 				Mem::Copy(byteDataPtr, startByteDataPtr, dataWidth);
   953 				byteDataPtr += dataWidth;
   954 				}
   955 			bitIndex += dataWidth;
   956 			}
   957 		}
   958 	}
   959 
   960 /**
   961 Converts binary data in 1 bit per pixel format to 8 bits per pixel format, where
   962 0 is converted to 0x00 and 1 is converted to 0xFF.
   963 
   964 @param aSrcData Pointer to a 1bpp source buffer.
   965 @param aDestDataPtr Pointer to a 8bpp destination buffer.
   966 @param aDestDataPtrLimit Pointer to the end position in destination buffer to convert to.
   967 */
   968 void Convert1BppTo8Bpp(TUint32 aSrcData, TUint8*& aDestDataPtr, const TUint8* aDestDataPtrLimit)
   969 	{
   970 	for (; aDestDataPtr < aDestDataPtrLimit; ++aDestDataPtr, aSrcData >>= 1)
   971 		{
   972 		if (aSrcData&1)
   973 			{
   974 			*aDestDataPtr = 0xFF;
   975 			}
   976 		}
   977 	}
   978 
   979 /**
   980 Decodes binary data for extra large monochrome glyph bitmap.
   981 
   982 @param aGlyphSize Size of glyph in pixels.
   983 @param aEncodedData Pointer to an encoded source buffer.
   984 @param aByteData Pointer to a destination buffer (8 bits per pixel).
   985 */
   986 void DecodeBinaryDataExLarge(const TSize& aGlyphSize, const TUint8* aEncodedData, TUint8* aByteData)
   987 	{
   988 	const TInt dataWidth = aGlyphSize.iWidth;
   989 	const TInt dataHeight = aGlyphSize.iHeight;
   990 	TInt bitIndex = 0;
   991 	TInt16 repeatCount = 0;
   992 
   993 	for (TInt charLine = 0; charLine < dataHeight; charLine += repeatCount) // for lines in the character...
   994 		{
   995 		repeatCount = Load16(aEncodedData + (bitIndex >> 3));
   996 		repeatCount >>= bitIndex & 7;
   997 		const TInt multiLineFlag = repeatCount & 1;
   998 		repeatCount >>= 1;
   999 		repeatCount &= 0xf;
  1000 		bitIndex += 5;
  1001 		if (multiLineFlag)
  1002 			{
  1003 			for (TInt currentline = 0; currentline < repeatCount; currentline++)
  1004 				{
  1005 				CopyCharLine(aByteData, dataWidth, aEncodedData + (bitIndex >> 3), bitIndex & 7, 1);
  1006 				bitIndex += dataWidth;
  1007 				}
  1008 			}
  1009 		else
  1010 			{
  1011 			CopyCharLine(aByteData, dataWidth, aEncodedData + (bitIndex >> 3), bitIndex & 7, repeatCount);
  1012 			bitIndex += dataWidth;
  1013 			}
  1014 		}
  1015 	}
  1016 
  1017 /**
  1018 Copies glyph image data line(s)(1 bit per pixel) to an 8 bit per pixel
  1019 destination buffer.
  1020 
  1021 @param aByteDataPtr Pointer to a destination buffer (8bpp).
  1022 @param aWidthInBytes Stride of the image.
  1023 @param aSrcData Pointer to a source buffer (1bpp).
  1024 @param aBitShift Number of bits the source data pointer will be shifted. 
  1025 @param aRepeatCount Number of lines to copy.
  1026 */
  1027 void CopyCharLine(TUint8*& aByteDataPtr, TInt aWidthInBytes, const TUint8* aSrcData, TInt aBitShift, TInt16 aRepeatCount)
  1028 	{
  1029 	aBitShift &= 7;
  1030 	TUint8* ptrLimit = aByteDataPtr + aWidthInBytes;
  1031 	TUint32* dataWord = (TUint32*)(TInt(aSrcData) &~ 3);
  1032 	aBitShift += (TInt(aSrcData) - TInt(dataWord)) << 3;
  1033 
  1034 	TUint8* startByteDataPtr = aByteDataPtr;
  1035 	TUint32 binaryData = 0;
  1036 	while (aByteDataPtr < ptrLimit)
  1037 		{
  1038 		binaryData = *dataWord++;
  1039 		binaryData >>= aBitShift;
  1040 		if (aBitShift)
  1041 			{
  1042 			binaryData |= (*dataWord << (32-aBitShift));
  1043 			}
  1044 		TUint8* wordLimit = aByteDataPtr + 32;
  1045 		if (wordLimit > ptrLimit)
  1046 			{
  1047 			wordLimit = ptrLimit;
  1048 			}
  1049 		Convert1BppTo8Bpp(binaryData, aByteDataPtr, wordLimit);
  1050 		}
  1051 
  1052 	while (aRepeatCount > 1)
  1053 		{
  1054 		Mem::Copy(aByteDataPtr, startByteDataPtr, aWidthInBytes);
  1055 		aByteDataPtr += aWidthInBytes;
  1056 		--aRepeatCount;
  1057 		}
  1058 	}
  1059 
  1060