121
|
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 |
|