|
1 // Copyright (c) 2007-2009 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 "vgimagecache.h" |
|
17 #include "directgdiadapter.h" |
|
18 |
|
19 /** |
|
20 Given a TDisplayMode, returns the closest TDisplayMode that is pixel-for-pixel-compatible |
|
21 with an OpenVG format, such that the given TDisplayMode may be converted into the result |
|
22 without loss of colour information. |
|
23 |
|
24 @param aDisplayMode Pixel format to find a match for. |
|
25 |
|
26 @return Closest TDisplayMode for which there is a OpenVG-compatible match. |
|
27 */ |
|
28 static TDisplayMode ClosestVgCompatibleDisplayMode (TDisplayMode aDisplayMode) |
|
29 { |
|
30 switch (aDisplayMode) |
|
31 { |
|
32 case EGray2: |
|
33 case EGray4: |
|
34 case EGray16: |
|
35 return EGray256; |
|
36 |
|
37 case EColor16: |
|
38 case EColor256: |
|
39 case EColor4K: |
|
40 return EColor64K; |
|
41 |
|
42 case EColor16M: |
|
43 return EColor16MU; |
|
44 |
|
45 default: |
|
46 return aDisplayMode; |
|
47 } |
|
48 } |
|
49 |
|
50 |
|
51 /** |
|
52 Image Cache Item constructor. |
|
53 */ |
|
54 CVgImageCache::CVgImageCacheItem::CVgImageCacheItem() |
|
55 { |
|
56 |
|
57 } |
|
58 |
|
59 /** |
|
60 Image Cache Item destructor. |
|
61 Destroys the VGImage owned by the cache item. |
|
62 */ |
|
63 CVgImageCache::CVgImageCacheItem::~CVgImageCacheItem() |
|
64 { |
|
65 vgDestroyImage(iImage); |
|
66 } |
|
67 |
|
68 |
|
69 |
|
70 /** |
|
71 Forms a 32-bit hash value from a 64-bit integer. |
|
72 |
|
73 @param aKey The 64-bit key to be hashed. |
|
74 @return 32-bit hash value. |
|
75 */ |
|
76 TUint32 CVgImageCache::Hash(const TInt64& aKey) |
|
77 { |
|
78 TPckgC<TInt64> bytes(aKey); |
|
79 return DefaultHash::Des8(bytes); |
|
80 } |
|
81 |
|
82 /** |
|
83 Image Cache constructor. |
|
84 Initialises the hashmap and double-linked queue |
|
85 */ |
|
86 CVgImageCache::CVgImageCache(TInt aMaxCacheSize) |
|
87 :iCacheItemMap(THashFunction32<TInt64>(CVgImageCache::Hash), TIdentityRelation<TInt64>()), |
|
88 iVgImageCache(_FOFF(CVgImageCacheItem, iLink)), |
|
89 iMaxCacheSizeInBytes(aMaxCacheSize) |
|
90 { |
|
91 } |
|
92 |
|
93 /** |
|
94 Image Cache destructor. |
|
95 Iterates through all the items in the cache and deletes them. |
|
96 */ |
|
97 CVgImageCache::~CVgImageCache() |
|
98 { |
|
99 // cycle through all the items and destroy the VGImages. |
|
100 TDblQueIter<CVgImageCacheItem> iter(iVgImageCache); |
|
101 CVgImageCacheItem* item; |
|
102 while((item=iter++)!=NULL) |
|
103 { |
|
104 DeleteItem(item); |
|
105 } |
|
106 iCacheItemMap.Close(); |
|
107 } |
|
108 |
|
109 /** |
|
110 Deletes a cache item. |
|
111 This removes the supplied item from the queue and the hashmap, |
|
112 destroys the VGImage in that item, and deletes the item itself. |
|
113 @param aItem The image cache item to be deleted. |
|
114 */ |
|
115 void CVgImageCache::DeleteItem(CVgImageCacheItem* aItem) |
|
116 { |
|
117 aItem->iLink.Deque(); |
|
118 iCacheSizeInBytes -= aItem->iImageSizeInBytes; |
|
119 iCacheItemMap.Remove(aItem->iSerialNumber); |
|
120 delete aItem; |
|
121 } |
|
122 |
|
123 /** |
|
124 Adds a VGImage to the cache using the associated CFbsBitmap as a reference. |
|
125 |
|
126 A new image cache item is created which stores the VGImage, the size of the image in pixels, |
|
127 the serial number of the CFbsBitmap (which acts as a unique identifier) and the touch count |
|
128 of the CFbsBitmap. The touch count determines the number of times the underlying data of |
|
129 the CFbsBitmap has changed. |
|
130 |
|
131 The least-recently used items will be removed from the cache to create space for the new item, if needed. |
|
132 |
|
133 @param aBitmap The bitmap from which the VGImage was created. |
|
134 @param aImage The VGImage to store in the cache. |
|
135 @param aOrigin The origin used to create a tiled VGImage. |
|
136 |
|
137 @return ETrue if the VGImage was successfully added to the cache, EFalse if not. |
|
138 */ |
|
139 TBool CVgImageCache::AddImage(const CFbsBitmap& aBitmap, VGImage& aImage, const TPoint& aOrigin) |
|
140 { |
|
141 // Calculate approximate size in bytes of image |
|
142 TDisplayMode vgCompatibleDisplayMode = ClosestVgCompatibleDisplayMode(aBitmap.DisplayMode()); |
|
143 TSize imageSize = aBitmap.SizeInPixels(); |
|
144 TInt dataStride = CFbsBitmap::ScanLineLength(imageSize.iWidth, vgCompatibleDisplayMode); |
|
145 TInt imageSizeInBytes = imageSize.iHeight * dataStride; |
|
146 // if size of image is too large to fit in cache |
|
147 if(imageSizeInBytes > iMaxCacheSizeInBytes) |
|
148 { |
|
149 return EFalse; |
|
150 } |
|
151 |
|
152 CVgImageCacheItem* newItem = new CVgImageCacheItem; |
|
153 if (newItem == NULL) |
|
154 { |
|
155 return EFalse; |
|
156 } |
|
157 |
|
158 // check there is enough room in the cache |
|
159 // i.e. less than user-specified max memory allowed for cache |
|
160 // if not enough space, remove items from end of cache until enough space is available. |
|
161 while(iMaxCacheSizeInBytes < iCacheSizeInBytes + imageSizeInBytes) |
|
162 { |
|
163 DeleteItem(iVgImageCache.Last()); |
|
164 } |
|
165 newItem->iSerialNumber = aBitmap.SerialNumber(); |
|
166 newItem->iImage = aImage; |
|
167 newItem->iTouchCount = aBitmap.TouchCount(); |
|
168 newItem->iOrigin = aOrigin; |
|
169 newItem->iImageSizeInBytes = imageSizeInBytes; |
|
170 TInt err = iCacheItemMap.Insert(newItem->iSerialNumber, newItem); |
|
171 if (err != KErrNone) |
|
172 { |
|
173 delete newItem; |
|
174 return EFalse; |
|
175 } |
|
176 iVgImageCache.AddFirst(*newItem); |
|
177 iCacheSizeInBytes += newItem->iImageSizeInBytes; |
|
178 return ETrue; |
|
179 } |
|
180 |
|
181 /** |
|
182 Retrieves the VGImage from the cache that was created from the supplied CFbsBitmap. |
|
183 The cache is first searched to find the item containing the VGImage that was created from the CFbsBitmap. |
|
184 If no matching item is found, no VGImage is returned. |
|
185 If the matching item is found, the touch count is checked to determine whether the |
|
186 CFbsBitmap has been updated since the stored VGImage was created from it. If it has, the matching item |
|
187 and VGImage is deleted from the cache and no VGImage is returned. |
|
188 If the matching item is found and the CFbsitmap has not been updated sionce the VGImage was created, |
|
189 the associated VGImage is returned. |
|
190 |
|
191 @param aBitmap The bitmap used to reference the item containing the VGImage. |
|
192 @param aOrigin The origin of the VGImage, relative to the top left corner of the source image. |
|
193 |
|
194 @return VG_INVALID_HANDLE if no VGImage exists for the supplied CFbsBitmap or if the stored VGImage is out of date. |
|
195 Otherwise the VGImage associated with the CFbsBitmap is returned. |
|
196 */ |
|
197 VGImage CVgImageCache::GetVgImageFromBitmap(const CFbsBitmap& aBitmap, const TPoint& aOrigin) |
|
198 { |
|
199 // search through cache to find the item with a matching bitmap ID |
|
200 CVgImageCacheItem** itemPtr = iCacheItemMap.Find(aBitmap.SerialNumber()); |
|
201 ++iNumMatchTries; |
|
202 if(itemPtr == NULL) |
|
203 { |
|
204 // searched all the way through cache and there is no matching image |
|
205 ++iNumMatchMisses; |
|
206 return VG_INVALID_HANDLE; |
|
207 } |
|
208 CVgImageCacheItem* item = *itemPtr; |
|
209 // Check whether the VGImage held by the item is up-to-date |
|
210 // - check touch counts are equal. |
|
211 // - check origins used for creating VGImage are equal. |
|
212 if (aBitmap.TouchCount() != item->iTouchCount || aOrigin != item->iOrigin) |
|
213 { |
|
214 // VGImage in item needs updating, so remove and delete the entry |
|
215 // and return NULL to indicate that a new entry needs to be created. |
|
216 DeleteItem(item); |
|
217 return VG_INVALID_HANDLE; |
|
218 } |
|
219 // VGImage is up-to date. |
|
220 // If item is not already at front of list, move it there |
|
221 if(!iVgImageCache.IsFirst(item)) |
|
222 { |
|
223 item->iLink.Deque(); |
|
224 iVgImageCache.AddFirst(*item); |
|
225 } |
|
226 return item->iImage; |
|
227 } |
|
228 |
|
229 // Test APIs |
|
230 |
|
231 /** |
|
232 Determines whether an item exists for a specified bitmap's serial number. |
|
233 |
|
234 @param aSerialNumber The unique identifier of a CFbsBitmap. |
|
235 |
|
236 @return ETrue if a matching item is found using the serial number. EFalse if not. |
|
237 */ |
|
238 TBool CVgImageCache::IsInCache(TInt64 aSerialNumber) |
|
239 { |
|
240 return (iCacheItemMap.Find(aSerialNumber) != NULL); |
|
241 } |
|
242 |
|
243 /** |
|
244 The touch count stored in the item associated with the supplied serial number. |
|
245 |
|
246 @param aSerialNumber The unique identifier of a CFbsBitmap. |
|
247 |
|
248 @return The touch count stored in the item associated with the supplied serial number. |
|
249 KErrNotFound if no matching item is found using the serial number. |
|
250 */ |
|
251 TInt CVgImageCache::TouchCount(TInt64 aSerialNumber) |
|
252 { |
|
253 CVgImageCacheItem** itemPtr = iCacheItemMap.Find(aSerialNumber); |
|
254 if(itemPtr == NULL) |
|
255 { |
|
256 // searched all the way through cache and there is no matching image |
|
257 return KErrNotFound; |
|
258 } |
|
259 return (*itemPtr)->iTouchCount; |
|
260 } |
|
261 |
|
262 /** |
|
263 The number of entries in the cache. |
|
264 @return The number of entries in the cache. |
|
265 */ |
|
266 TInt CVgImageCache::NumEntries() const |
|
267 { |
|
268 return iCacheItemMap.Count(); |
|
269 } |
|
270 |
|
271 /** |
|
272 Returns a list of the serial numbers of all the cache items, with the most-recently used item at ordinal 0 |
|
273 and the least-recently used item and the end of the list. |
|
274 |
|
275 @param aSerialNumberList A reference to a list in which to return the serial number list. |
|
276 @param aListSize The number of entries allocated for the list. |
|
277 */ |
|
278 void CVgImageCache::GetOrderedCacheEntries(TInt64& aSerialNumberList, TInt aListSize) |
|
279 { |
|
280 GRAPHICS_ASSERT_ALWAYS(aSerialNumberList, EDirectGdiPanicInvalidPointArray) |
|
281 TDblQueIter<CVgImageCacheItem> iter(iVgImageCache); |
|
282 |
|
283 TInt n = iCacheItemMap.Count(); |
|
284 // If n is greater than number of entries in list, restrict to number of entries. |
|
285 if (n > aListSize) n = aListSize; |
|
286 for (TInt ii = 0; ii < n; ++ii) |
|
287 { |
|
288 CVgImageCacheItem* item = iter++; |
|
289 (&aSerialNumberList)[ii] = item->iSerialNumber; |
|
290 } |
|
291 |
|
292 // If n is less than number of entries in list, pad out entries with 0 |
|
293 // (i.e. invlaid serial numbers) |
|
294 while (n < aListSize) |
|
295 { |
|
296 (&aSerialNumberList)[n++] = 0; |
|
297 } |
|
298 } |
|
299 |
|
300 /** |
|
301 The total size of the cache in bytes. |
|
302 @return The total size of the cache in bytes. |
|
303 */ |
|
304 TInt CVgImageCache::CacheSizeInBytes() const |
|
305 { |
|
306 return iCacheSizeInBytes; |
|
307 } |
|
308 |
|
309 /** |
|
310 The maximum size of the cache in bytes. |
|
311 @return The maximum size of the cache in bytes. |
|
312 */ |
|
313 TInt CVgImageCache::MaxCacheSize() const |
|
314 { |
|
315 return iMaxCacheSizeInBytes; |
|
316 } |
|
317 |
|
318 /** |
|
319 Resets the cache. Iterates through all the items in the cache and deletes them. |
|
320 */ |
|
321 void CVgImageCache::ResetCache() |
|
322 { |
|
323 // cycle through all the items and destroy the VGImages. |
|
324 TDblQueIter<CVgImageCacheItem> iter(iVgImageCache); |
|
325 CVgImageCacheItem* item; |
|
326 while((item=iter++)!=NULL) |
|
327 { |
|
328 DeleteItem(item); |
|
329 } |
|
330 } |
|
331 |
|
332 /** |
|
333 Sets the maximum size in bytes of the cache. Checks the current size of the |
|
334 cache and sets the maximum cache size if the current cache size is smaller |
|
335 or equal to aCacheSize. |
|
336 @param aMaxCacheSize The maximum size in bytes to allow for the cache. |
|
337 @return KErrNone if the maximum cache size has been changed successfully, |
|
338 KErrArgument if aMaxCacheSize is smaller than the current cache size. |
|
339 */ |
|
340 TInt CVgImageCache::SetMaxCacheSize(TInt aMaxCacheSize) |
|
341 { |
|
342 if (iCacheSizeInBytes <= aMaxCacheSize) |
|
343 { |
|
344 iMaxCacheSizeInBytes = aMaxCacheSize; |
|
345 return KErrNone; |
|
346 } |
|
347 |
|
348 return KErrArgument; |
|
349 } |