Update contrib.
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".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
16 #include "glyphatlas.h"
17 #include "OstTraceDefinitions.h"
18 #ifdef OST_TRACE_COMPILER_IN_USE
19 #include "glyphatlasTraces.h"
23 extern void Panic(TFbsPanic aPanic);
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);
31 // === CGlyphAtlas Functions ===
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
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)
47 iMaxCacheSizeLow = ( KGlyphAtlasNoCacheLimit == aMaxCacheSizeInBytes )
48 ? KGlyphAtlasLowMemCacheLimitDefault
49 : ( aMaxCacheSizeInBytes / KGlyphAtlasLowMemCacheLimitDivisor );
53 Glyph Atlas destructor.
54 Frees all the RSgImage handles, frees all the allocated system memory, and
55 closes the Graphics Resource driver.
57 CGlyphAtlas::~CGlyphAtlas()
59 // cycle through all the font entries and destroy them
60 for (TInt ii = iFontEntryArray.Count()-1; ii >= 0; --ii)
62 DeleteFontEntry(iFontEntryArray[ii].iEntry);
64 iFontEntryArray.Close();
65 __ASSERT_DEBUG(iLruPageList.IsEmpty(), Panic(EFbsPanicGlyphAtlasInconsistentState));
67 // there shouldn't be any remaining pages, but if there are, destroy them.
68 while (!iLruPageList.IsEmpty())
70 delete iLruPageList.First();
76 Factory constructor method. Creates a new glyph atlas.
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.
83 @return A pointer to the newly-constructed atlas
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.
88 CGlyphAtlas* CGlyphAtlas::NewL(TInt aMaxCacheSizeInBytes)
90 CGlyphAtlas* self = new (ELeave) CGlyphAtlas(aMaxCacheSizeInBytes);
91 CleanupStack::PushL(self);
93 CleanupStack::Pop(); // self;
98 Two-phase constructor.
99 @leave A system wide error code if RSgDriver failed to open.
101 void CGlyphAtlas::ConstructL()
103 User::LeaveIfError(iSgDriver.Open());
107 Retrieves a glyph from the atlas.
108 If the glyph is found, the glyph data passed in is populated.
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.
115 TInt CGlyphAtlas::GetGlyph(const CBitmapFont& aFont, TUint aGlyphCode, TGlyphImageInfo& aGlyphImageInfo)
117 OstTraceExt2( TRACE_NORMAL, CGLYPHATLAS_GETGLYPH, "> f=%x; gc=%04x",(TUint)&aFont, aGlyphCode);
119 CGlyphAtlasFontEntry* fontEntry = FindFontEntry(aFont);
122 OstTrace0( TRACE_NORMAL, CGLYPHATLAS_GETGLYPH_END2, "< KErrNotFound");
125 TInt err = fontEntry->GetGlyph(aGlyphCode, aGlyphImageInfo);
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);
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.
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.
146 TInt CGlyphAtlas::AddGlyph(const CBitmapFont& aFont, const TAddGlyphArgs& aArgs, TGlyphImageInfo& aGlyphImageInfo)
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());
152 // Find font entry and create if none found
153 CGlyphAtlasFontEntry* fontEntry = FindFontEntry(aFont);
154 TBool isNewFont = EFalse;
157 // Create a new font.
158 fontEntry = CreateFontEntry(aFont);
161 OstTraceDef0(OST_TRACE_CATEGORY_DEBUG, TRACE_NORMAL, CGLYPHATLAS_ADDGLYPH_END2, "< KErrNoMemory");
166 TInt glyphSizeInBytes = 0;
167 TInt err = fontEntry->AddGlyph(aArgs, aGlyphImageInfo, glyphSizeInBytes);
172 DeleteFontEntry(fontEntry);
174 OstTraceDef1(OST_TRACE_CATEGORY_DEBUG, TRACE_NORMAL, CGLYPHATLAS_ADDGLYPH_END3, "< err=%d", err);
177 iCacheSizeInBytes += glyphSizeInBytes;
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)
185 TBool morePagesToDelete = ETrue;
186 while ((iCacheSizeInBytes > iMaxCacheSizeInBytes) && morePagesToDelete)
188 morePagesToDelete = DeleteLeastRecentlyUsedPage(EFalse);
192 OstTraceDefExt2(OST_TRACE_CATEGORY_DEBUG, TRACE_NORMAL, CGLYPHATLAS_ADDGLYPH_END1, "< id=%08x%08x",
193 I64HIGH(aGlyphImageInfo.iImageId.iId), I64LOW(aGlyphImageInfo.iImageId.iId));
199 Releases all glyphs associated with a particular font when it has been
200 released by the font system.
202 @param aFont The font which is released.
204 void CGlyphAtlas::FontReleased(const CBitmapFont& aFont)
206 OstTraceDef1(OST_TRACE_CATEGORY_DEBUG, TRACE_NORMAL, CGLYPHATLAS_FONTRELEASED, "> f=%x", (TUint)&aFont);
208 TInt index = iFontEntryArray.FindInUnsignedKeyOrder(TFontEntryMap(&aFont, NULL));
209 if (KErrNotFound == index)
211 OstTraceDef0(OST_TRACE_CATEGORY_DEBUG, TRACE_NORMAL, CGLYPHATLAS_FONTRELEASED_END2, "< KErrNotFound");
214 CGlyphAtlasFontEntry* fontEntry = iFontEntryArray[index].iEntry;
215 iCacheSizeInBytes -= fontEntry->SizeInBytes();
217 iFontEntryArray.Remove(index);
218 OstTraceDef0(OST_TRACE_CATEGORY_DEBUG, TRACE_NORMAL, CGLYPHATLAS_FONTRELEASED_END3, "< KErrNone");
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
226 @param aFont The font to match an entry with.
227 @return The font entry if a match is found, NULL if not.
229 CGlyphAtlasFontEntry* CGlyphAtlas::FindFontEntry(const CBitmapFont& aFont) const
231 TFontEntryMap entryToMatch(&aFont, NULL);
232 TInt index = iFontEntryArray.FindInUnsignedKeyOrder(entryToMatch);
233 if (KErrNotFound == index)
237 return iFontEntryArray[index].iEntry;
241 Deletes the given font entry.
242 The mapping from the font to the font entry is removed.
244 @param aFontEntry The entry to delete.
246 void CGlyphAtlas::DeleteFontEntry(CGlyphAtlasFontEntry* aFontEntry)
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)
253 iFontEntryArray.Remove(index);
255 iCacheSizeInBytes -= aFontEntry->SizeInBytes();
260 Moves the given page to the front (the position of the most recently used page)
261 of the usage order list.
263 @param aPage The most recently used page.
265 void CGlyphAtlas::MovePageToFront(CGlyphAtlasPage& aPage)
267 aPage.MoveToFirstInQueue(iLruPageList);
271 Creates a font entry from the given font and adds a mapping from the font
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.
277 @param aFont The font used to create a font entry from.
278 @return A new font entry if successful, NULL if not.
280 CGlyphAtlasFontEntry* CGlyphAtlas::CreateFontEntry(const CBitmapFont& aFont)
282 CGlyphAtlasFontEntry* fontEntry = new CGlyphAtlasFontEntry(aFont, *this);
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));
300 Deletes the least recently used page and removes it from the list of pages
303 @param aAllowMruPageDeletion ETrue if the most recently used page can be deleted,
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,
309 TBool CGlyphAtlas::DeleteLeastRecentlyUsedPage(TBool aAllowMruPageDeletion)
311 OstTraceDef1(OST_TRACE_CATEGORY_DEBUG, TRACE_NORMAL, CGLYPHATLAS_DELETELEASTRECENTLYUSEDPAGE, "> mru=%d", aAllowMruPageDeletion );
313 CGlyphAtlasPage* lruPage = NULL;
314 if (!iLruPageList.IsEmpty())
316 lruPage = iLruPageList.Last();
317 if (!aAllowMruPageDeletion && (lruPage == iLruPageList.First()))
322 TBool canDeleteMorePages = EFalse;
325 iCacheSizeInBytes -= lruPage->SizeInBytes();
326 CGlyphAtlasFontEntry& fontEntry = lruPage->FontEntry();
327 fontEntry.DeletePage(lruPage);
329 if (fontEntry.IsEmpty())
331 DeleteFontEntry(&fontEntry);
333 canDeleteMorePages = !iLruPageList.IsEmpty();
335 OstTraceDefExt2(OST_TRACE_CATEGORY_DEBUG, TRACE_NORMAL, CGLYPHATLAS_DELETELEASTRECENTLYUSEDPAGE_END, "< more=%u; size=%u", (TUint)canDeleteMorePages, iCacheSizeInBytes);
336 return canDeleteMorePages;
340 Utility function that calculates the number of unique fonts associated with the atlas.
341 @return Number of fonts in the atlas.
343 TInt CGlyphAtlas::FontCount() const
345 return iFontEntryArray.Count();
349 Utility function that calculates the number of glyphs across all fonts stored in
351 @return Number of glyphs in the atlas.
353 TInt CGlyphAtlas::GlyphCount() const
356 for (TInt ii = iFontEntryArray.Count() - 1; ii >= 0; --ii)
358 glyphCount += iFontEntryArray[ii].iEntry->GlyphCount();
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.
368 TInt CGlyphAtlas::GlyphCount(const CBitmapFont& aFont) const
370 CGlyphAtlasFontEntry* fontEntry = FindFontEntry(aFont);
371 return (fontEntry) ? fontEntry->GlyphCount() : 0;
374 void CGlyphAtlas::GetGlyphCacheMetrics( TGlyphCacheMetrics& aGlyphCacheMetrics )
376 aGlyphCacheMetrics.iMaxCacheSizeInBytes = iMaxCacheSizeInBytes;
377 aGlyphCacheMetrics.iMaxCacheSizeHigh = iMaxCacheSizeHigh;
378 aGlyphCacheMetrics.iMaxCacheSizeLow = iMaxCacheSizeLow;
379 aGlyphCacheMetrics.iCacheSizeInBytes = iCacheSizeInBytes;
380 aGlyphCacheMetrics.iGpuCacheSizeLimitIsMax = iGpuCacheSizeLimitIsMax;
384 Function to release the GPU cache. Called in response to the GoomMonitor's
385 requirement to reduce GPU memory use.
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.
390 void CGlyphAtlas::ReleaseGpuMemory( TInt /*aBytes*/, TInt /*aFlags*/ )
392 OstTraceDefExt2( OST_TRACE_CATEGORY_DEBUG, TRACE_NORMAL, CGLYPHATLAS_RELEASEGPUMEMORY, "> max=%d; size=%d", iMaxCacheSizeInBytes, iCacheSizeInBytes);
394 if ( iCacheSizeInBytes > 0 )
396 while( DeleteLeastRecentlyUsedPage(ETrue) )
402 // If appropriate, reduce the cache-size limit.
403 if ( GpuCacheSizeLimitIsMax() )
405 SwitchGpuCacheSizeLimit();
408 OstTraceDefExt2( OST_TRACE_CATEGORY_DEBUG, TRACE_NORMAL, CGLYPHATLAS_RELEASEGPUMEMORY_EXIT, "< max=%d; size=%d", iMaxCacheSizeInBytes, iCacheSizeInBytes);
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.
415 @param aFlags. The flags conveyed from the GOoM monitor framework.
417 void CGlyphAtlas::InstateGpuMemory( TInt /*aFlags*/ )
419 OstTraceDef1(OST_TRACE_CATEGORY_DEBUG, TRACE_NORMAL, CGLYPHATLAS_INSTATEGPUMEMORY, "> max=%d", iMaxCacheSizeInBytes );
421 // If appropriate, reinstate the full cache-size limit.
422 if ( !GpuCacheSizeLimitIsMax() )
424 SwitchGpuCacheSizeLimit();
427 OstTraceDef1(OST_TRACE_CATEGORY_DEBUG, TRACE_NORMAL, CGLYPHATLAS_INSTATEGPUMEMORY_EXIT, "< max=%d", iMaxCacheSizeInBytes );
431 Utility function to toggle between full and reduced GPU cache-size limits.
433 Use in conjunction with TBool GpuCacheSizeLimitIsMax()
435 void CGlyphAtlas::SwitchGpuCacheSizeLimit()
437 if ( GpuCacheSizeLimitIsMax() )
439 // The short-circuit operator obviates tautological conditionals.
440 while ( (iCacheSizeInBytes >= iMaxCacheSizeLow) && DeleteLeastRecentlyUsedPage(ETrue) )
445 iMaxCacheSizeInBytes = iMaxCacheSizeLow;
446 iGpuCacheSizeLimitIsMax = EFalse;
450 iMaxCacheSizeInBytes = iMaxCacheSizeHigh;
451 iGpuCacheSizeLimitIsMax = ETrue;
457 Utility function to report whether the GPU cache-size limit is set to the maximum permissible
458 level, or to its reduced level.
460 @return ETrue if the cache-size is set to the maximum permissible limit.
461 EFalse if it is set to the reduced limit.
463 TBool CGlyphAtlas::GpuCacheSizeLimitIsMax() const
465 return iGpuCacheSizeLimitIsMax;
468 // === CGlyphAtlasFontEntry Functions ===
470 Font entry constructor.
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.
475 CGlyphAtlasFontEntry::CGlyphAtlasFontEntry(const CBitmapFont& aFont, CGlyphAtlas& aGlyphAtlas)
477 iPageArray(32, _FOFF(TPageMap, iGlyphCode)),
483 Font entry destructor.
484 Destroys the pages owned by the font entry.
486 CGlyphAtlasFontEntry::~CGlyphAtlasFontEntry()
488 // cycle through all the font entries and destroy them
489 for (TInt ii = iPageArray.Count()-1; ii >= 0; --ii)
491 DeletePage(iPageArray[ii].iPage);
493 __ASSERT_DEBUG(iSizeInBytes == 0, Panic(EFbsPanicGlyphAtlasInconsistentState));
498 Deletes the given page.
499 The page mapping is removed and the page is deleted.
501 @param aPage The page to delete.
503 void CGlyphAtlasFontEntry::DeletePage(CGlyphAtlasPage* aPage)
505 __ASSERT_DEBUG(aPage, Panic(EFbsPanicGlyphAtlasInconsistentState));
506 __ASSERT_DEBUG(iPageArray.Count() > 0, Panic(EFbsPanicGlyphAtlasInconsistentState));
508 TInt numGlyphsInPage = aPage->GlyphCount();
510 for (TInt ii = 0; ii < numGlyphsInPage; ++ii)
512 TInt index = iPageArray.FindInUnsignedKeyOrder(TPageMap(aPage->GlyphCodeAt(ii), NULL));
514 __ASSERT_DEBUG(KErrNotFound != index, Panic(EFbsPanicGlyphAtlasInconsistentState));
516 if (KErrNotFound != index)
518 iPageArray.Remove(index);
519 iPageArray.GranularCompress();
522 iSizeInBytes -= aPage->SizeInBytes();
528 Adds a glyph to the font from a bitmap glyph and gets the glyph image info back.
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.
536 TInt CGlyphAtlasFontEntry::AddGlyph(const CGlyphAtlas::TAddGlyphArgs& aArgs, TGlyphImageInfo& aGlyphImageInfo, TInt& aSizeInBytes)
538 CGlyphAtlasPage* newPage = new CGlyphAtlasPage(*this);
544 TInt err = newPage->AddGlyph(aArgs, aGlyphImageInfo, aSizeInBytes);
551 err = iPageArray.InsertInUnsignedKeyOrder(TPageMap(aArgs.iGlyphCode, newPage));
552 __ASSERT_DEBUG(KErrAlreadyExists != err, Panic(EFbsPanicGlyphAtlasInconsistentState));
558 iSizeInBytes += aSizeInBytes;
559 iAtlas.MovePageToFront(*newPage);
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.
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.
573 TInt CGlyphAtlasFontEntry::GetGlyph(TUint aGlyphCode, TGlyphImageInfo& aGlyphImageInfo)
575 TInt index = iPageArray.FindInUnsignedKeyOrder(TPageMap(aGlyphCode, NULL));
576 if (KErrNotFound == index)
580 CGlyphAtlasPage* page = iPageArray[index].iPage;
581 page->GetGlyph(aGlyphCode, aGlyphImageInfo);
582 iAtlas.MovePageToFront(*page);
587 Gets the font associated with the font entry.
589 @return The font associated with this entry.
591 const CBitmapFont& CGlyphAtlasFontEntry::Font() const
597 Gets the amount of memory allocated for all the image data for this font.
599 @return The size of the font's image data in bytes.
601 TInt CGlyphAtlasFontEntry::SizeInBytes() const
607 Tests whether the font entry has any pages.
609 @return ETrue if the font entry does not contain any pages, EFalse if it does..
611 TBool CGlyphAtlasFontEntry::IsEmpty() const
613 if (iPageArray.Count() == 0)
615 __ASSERT_DEBUG(iSizeInBytes == 0, Panic(EFbsPanicGlyphAtlasInconsistentState));
622 Gets the glyph atlas the font entry belongs to.
624 @return The font entry's glyph atlas.
626 CGlyphAtlas& CGlyphAtlasFontEntry::GlyphAtlas() const
632 @return The number of glyphs this font entry has.
634 TInt CGlyphAtlasFontEntry::GlyphCount() const
637 for (TInt ii = iPageArray.Count() - 1; ii >= 0; --ii)
639 glyphCount += iPageArray[ii].iPage->GlyphCount();
645 // === CGlyphAtlasPage Functions ===
650 @param aFontEntry The font entry to which the page is associated.
652 CGlyphAtlasPage::CGlyphAtlasPage(CGlyphAtlasFontEntry& aFontEntry)
653 :iFontEntry(aFontEntry)
659 Releases the RSgImage handles held by the page.
660 Removes the page from the Glyph Atlas' LRU page array.
662 CGlyphAtlasPage::~CGlyphAtlasPage()
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).
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.
684 TInt CGlyphAtlasPage::AddGlyph(const CGlyphAtlas::TAddGlyphArgs& aArgs, TGlyphImageInfo& aGlyphImageInfo, TInt& aSizeInBytes)
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)
692 iMetrics = *aArgs.iMetrics;
693 iGlyphCode = aArgs.iGlyphCode;
696 aGlyphImageInfo.iImageId = KSgNullDrawableId;
697 aGlyphImageInfo.iPosX = iPosX;
698 aGlyphImageInfo.iPosY = iPosY;
699 aGlyphImageInfo.iMetrics = iMetrics;
704 info.iSizeInPixels = glyphSize;
705 info.iUsage = ESgUsageBitOpenVgImage;
706 info.iPixelFormat = EUidPixelFormatA_8;
708 const TInt KDataArraySize = 256;
709 TUint8 byteDataArray[KDataArraySize];
710 TUint8* tempBuf = NULL;
711 TUint8* byteDataBuf = NULL;
712 TGlyphBitmapType glyphBitmapType = iFontEntry.Font().GlyphBitmapType();
714 switch (glyphBitmapType)
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)
723 tempBuf = (TUint8*) User::AllocZ(dataStride * glyphSize.iHeight);
728 byteDataBuf = tempBuf;
732 // fill array with zeros.
733 Mem::FillZ(&byteDataArray, KDataArraySize);
736 if (glyphSize.iWidth >32)
738 DecodeBinaryDataExLarge(glyphSize, aArgs.iBitmapPointer, byteDataBuf);
742 DecodeBinaryData(glyphSize, aArgs.iBitmapPointer, byteDataBuf);
746 case EAntiAliasedGlyphBitmap:
747 buf = const_cast<TUint8*>(aArgs.iBitmapPointer);
748 dataStride = glyphSize.iWidth;
751 return KErrNotSupported;
754 TInt err = iGlyphImage.Create(info, buf, dataStride);
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)
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);
774 aSizeInBytes = glyphSize.iHeight * glyphSize.iWidth;
775 iGlyphCode = aArgs.iGlyphCode;
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;
784 aGlyphImageInfo.iPosX = iPosX;
785 aGlyphImageInfo.iPosY = iPosY;
786 aGlyphImageInfo.iImageId = iGlyphImage.Id();
787 aGlyphImageInfo.iMetrics = iMetrics;
792 Retrieves the glyph image information for the given glyph code necessary to be
793 able to use the glyph in another process.
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.
799 void CGlyphAtlasPage::GetGlyph(TUint aGlyphCode, TGlyphImageInfo& aGlyphImageInfo) const
801 __ASSERT_DEBUG(iGlyphCode == aGlyphCode, Panic(EFbsPanicGlyphAtlasInconsistentState));
802 aGlyphImageInfo.iMetrics = iMetrics;
803 aGlyphImageInfo.iPosX = iPosX;
804 aGlyphImageInfo.iPosY = iPosY;
805 aGlyphImageInfo.iImageId = iGlyphImage.Id();
809 Gets the amount of memory allocated for the image data for this page.
811 @return The size of the page's image data in bytes.
813 TInt CGlyphAtlasPage::SizeInBytes() const
819 Gets the glyph code at the given index associated with the page.
821 @param aIndex The index of the glyph code within the page.
822 @return The glyph code at the given index.
824 TUint CGlyphAtlasPage::GlyphCodeAt(TInt aIndex) const
826 __ASSERT_DEBUG(0 == aIndex, Panic(EFbsPanicGlyphAtlasInconsistentState));
831 Gets the number of glyphs stored in the page.
833 @return The number of glyphs in the page.
835 TInt CGlyphAtlasPage::GlyphCount() const
841 Gets the font entry which owns the page.
843 @return The font entry which owns the page.
845 CGlyphAtlasFontEntry& CGlyphAtlasPage::FontEntry() const
851 void CGlyphAtlasPage::MoveToFirstInQueue(TDblQue<CGlyphAtlasPage>& aList)
853 if(!aList.IsFirst(this))
856 aList.AddFirst(*this);
860 // === Static Utility Functions ===
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.
867 static TInt16 Load16(const TUint8* aPtr)
869 return TInt16(aPtr[0]+(aPtr[1]<<8));
873 Decodes binary data for monochrome glyph bitmap.
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).
879 void DecodeBinaryData(const TSize& aGlyphSize, const TUint8* aEncodedData, TUint8* aByteData)
881 const TInt dataHeight = aGlyphSize.iHeight;
882 const TInt dataWidth = aGlyphSize.iWidth;
883 TUint32 binaryData = 0;
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]
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...
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)
909 // move bit index to point to first bit of image data
911 // end pointer of destination buffer for this block of data to fill
912 byteDataPtrLimit = aByteData + dataWidth * (charLine + repeatCount);
915 while (byteDataPtr < byteDataPtrLimit)
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.
929 binaryData |= (*charDataWord << (32-bitShift));
931 Convert1BppTo8Bpp(binaryData, byteDataPtr, byteDataPtr + dataWidth);
932 // Move bit index to beginning of next block
933 bitIndex += dataWidth;
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;
945 binaryData |= (*charDataWord << (32-bitShift));
947 TUint8* startByteDataPtr = byteDataPtr;
948 Convert1BppTo8Bpp(binaryData, byteDataPtr, byteDataPtr + dataWidth);
950 while (byteDataPtr < byteDataPtrLimit)
952 Mem::Copy(byteDataPtr, startByteDataPtr, dataWidth);
953 byteDataPtr += dataWidth;
955 bitIndex += dataWidth;
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.
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.
968 void Convert1BppTo8Bpp(TUint32 aSrcData, TUint8*& aDestDataPtr, const TUint8* aDestDataPtrLimit)
970 for (; aDestDataPtr < aDestDataPtrLimit; ++aDestDataPtr, aSrcData >>= 1)
974 *aDestDataPtr = 0xFF;
980 Decodes binary data for extra large monochrome glyph bitmap.
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).
986 void DecodeBinaryDataExLarge(const TSize& aGlyphSize, const TUint8* aEncodedData, TUint8* aByteData)
988 const TInt dataWidth = aGlyphSize.iWidth;
989 const TInt dataHeight = aGlyphSize.iHeight;
991 TInt16 repeatCount = 0;
993 for (TInt charLine = 0; charLine < dataHeight; charLine += repeatCount) // for lines in the character...
995 repeatCount = Load16(aEncodedData + (bitIndex >> 3));
996 repeatCount >>= bitIndex & 7;
997 const TInt multiLineFlag = repeatCount & 1;
1003 for (TInt currentline = 0; currentline < repeatCount; currentline++)
1005 CopyCharLine(aByteData, dataWidth, aEncodedData + (bitIndex >> 3), bitIndex & 7, 1);
1006 bitIndex += dataWidth;
1011 CopyCharLine(aByteData, dataWidth, aEncodedData + (bitIndex >> 3), bitIndex & 7, repeatCount);
1012 bitIndex += dataWidth;
1018 Copies glyph image data line(s)(1 bit per pixel) to an 8 bit per pixel
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.
1027 void CopyCharLine(TUint8*& aByteDataPtr, TInt aWidthInBytes, const TUint8* aSrcData, TInt aBitShift, TInt16 aRepeatCount)
1030 TUint8* ptrLimit = aByteDataPtr + aWidthInBytes;
1031 TUint32* dataWord = (TUint32*)(TInt(aSrcData) &~ 3);
1032 aBitShift += (TInt(aSrcData) - TInt(dataWord)) << 3;
1034 TUint8* startByteDataPtr = aByteDataPtr;
1035 TUint32 binaryData = 0;
1036 while (aByteDataPtr < ptrLimit)
1038 binaryData = *dataWord++;
1039 binaryData >>= aBitShift;
1042 binaryData |= (*dataWord << (32-aBitShift));
1044 TUint8* wordLimit = aByteDataPtr + 32;
1045 if (wordLimit > ptrLimit)
1047 wordLimit = ptrLimit;
1049 Convert1BppTo8Bpp(binaryData, aByteDataPtr, wordLimit);
1052 while (aRepeatCount > 1)
1054 Mem::Copy(aByteDataPtr, startByteDataPtr, aWidthInBytes);
1055 aByteDataPtr += aWidthInBytes;