|
1 // Copyright (c) 2008-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 "examplerasterizer.h" |
|
17 #include <s32mem.h> |
|
18 #include <fbs.h> |
|
19 |
|
20 /** Create a new example rasterizer. |
|
21 |
|
22 @return A pointer to a newly constructed CFbsRasterizer object if successful, |
|
23 or NULL if no memory is available. |
|
24 */ |
|
25 EXPORT_C CFbsRasterizer* CFbsRasterizer::New() |
|
26 { |
|
27 return new CExampleRasterizer; |
|
28 } |
|
29 |
|
30 |
|
31 /** Constructor. |
|
32 */ |
|
33 CExampleRasterizer::CExampleRasterizer() |
|
34 : iRegisteredBmps(_FOFF(CRegisteredBitmap, iLink)), iRecentBmps(_FOFF(CRegisteredBitmap, iLink)) |
|
35 {} |
|
36 |
|
37 /** Destructor. |
|
38 */ |
|
39 CExampleRasterizer::~CExampleRasterizer() |
|
40 { |
|
41 while (!iRegisteredBmps.IsEmpty()) |
|
42 { |
|
43 delete iRegisteredBmps.First(); |
|
44 } |
|
45 while (!iRecentBmps.IsEmpty()) |
|
46 { |
|
47 delete iRecentBmps.First(); |
|
48 } |
|
49 delete iIdle; |
|
50 } |
|
51 |
|
52 /** Register a bitmap with this rasterizer for rendering. |
|
53 |
|
54 In this example an extended bitmap is a tricolour flag with three coloured stripes of the same size |
|
55 being either vertically or horizontally oriented. The colours to be used in the flag and a TUint8 |
|
56 that specifies horizontal or vertical stripes are passed in the aBitmapDesc.iData parameter, which |
|
57 should point to a buffer containing the three stripe colours first, each colour as three TUint8 |
|
58 values, followed by a TUint8 value where 1 means horizontal stripes and 0 means vertical stripes. |
|
59 |
|
60 The only display modes supported by this example rasterizer are EGray256, EColor64K, EColor16MU and EColor16MAP. |
|
61 |
|
62 If the rasterizer cannot allocate enough memory for rendering the extended bitmap this function |
|
63 will return silently. If an unsupported display mode is passed this function will return silently. |
|
64 |
|
65 @see CFbsRasterizer::BeginBitmap() |
|
66 @see EndBitmap() |
|
67 */ |
|
68 void CExampleRasterizer::BeginBitmap(TInt64 aBitmapId, const TBitmapDesc& aBitmapDesc, const TRegion* aRegionOfInterest) |
|
69 { |
|
70 // Check that the passed extended bitmap description is valid |
|
71 if ((aBitmapDesc.iSizeInPixels.iWidth <= 0) || (aBitmapDesc.iSizeInPixels.iHeight <= 0) |
|
72 // This test rasterizer only supports EGray256, EColor64K, EColor16MU and EColor16MAP |
|
73 || ((aBitmapDesc.iDispMode != EGray256) && (aBitmapDesc.iDispMode != EColor64K) && (aBitmapDesc.iDispMode != EColor16MU) && (aBitmapDesc.iDispMode != EColor16MAP)) |
|
74 || (aBitmapDesc.iDataType != KUidExampleExtendedBitmap) |
|
75 || (aBitmapDesc.iData == NULL) |
|
76 || (aBitmapDesc.iDataSize <= 0)) |
|
77 { |
|
78 #ifdef _DEBUG |
|
79 RDebug::Printf("Example Rasterizer Error: Invalid TBitmapDesc passed to CExampleRasterizer::BeginBitmap()"); |
|
80 #endif // _DEBUG |
|
81 return; |
|
82 } |
|
83 |
|
84 // Check if the bitmap is already registered |
|
85 CRegisteredBitmap* foundRegBmp = RegisteredBitmap(aBitmapId); |
|
86 if (!foundRegBmp) |
|
87 { |
|
88 // Not registered: check if the bitmap is in the cache of recently used bitmaps |
|
89 foundRegBmp = RecentBitmap(aBitmapId); |
|
90 if (foundRegBmp) |
|
91 { |
|
92 // Take the bitmap out of the cache and put it in the list of registered bitmaps |
|
93 foundRegBmp->iLink.Deque(); |
|
94 iTotalRecentBmpSize -= foundRegBmp->iBufLength; |
|
95 iRegisteredBmps.AddLast(*foundRegBmp); |
|
96 } |
|
97 } |
|
98 if (foundRegBmp) |
|
99 { |
|
100 #ifdef _DEBUG |
|
101 // Make sure an extended bitmap is not registered more than once with different attributes |
|
102 if ((foundRegBmp->iSizeInPixels != aBitmapDesc.iSizeInPixels) |
|
103 || (foundRegBmp->iDispMode != aBitmapDesc.iDispMode) |
|
104 || (foundRegBmp->iDataType != aBitmapDesc.iDataType)) |
|
105 { |
|
106 RDebug::Printf("Example Rasterizer Error: CExampleRasterizer::BeginBitmap() called for an extended bitmap that has already been registered with a different TBitmapDesc"); |
|
107 } |
|
108 #endif // _DEBUG |
|
109 |
|
110 // This bitmap is already registered, just increment its reference count and return |
|
111 foundRegBmp->iRefCount++; |
|
112 return; |
|
113 } |
|
114 |
|
115 // Get the scanline length we should use for this display mode as the scanlines we draw must be 32-bit aligned |
|
116 TInt scanLineLength = CFbsBitmap::ScanLineLength(aBitmapDesc.iSizeInPixels.iWidth, aBitmapDesc.iDispMode); |
|
117 // Create a CRegisteredBitmap object to save the pre-rendered bitmap |
|
118 TInt bufLength = scanLineLength * aBitmapDesc.iSizeInPixels.iHeight; |
|
119 // Allocate bufLength extra bytes for the embedded pixel buffer |
|
120 CRegisteredBitmap* regBmp = new(bufLength) CRegisteredBitmap(aBitmapId, aBitmapDesc, bufLength); |
|
121 if (!regBmp) |
|
122 { |
|
123 #ifdef _DEBUG |
|
124 RDebug::Printf("Example Rasterizer Error: Failed to allocate memory"); |
|
125 #endif // _DEBUG |
|
126 return; |
|
127 } |
|
128 |
|
129 // Pre-render the flag that the extended bitmap represents |
|
130 RMemReadStream readStream; |
|
131 readStream.Open(aBitmapDesc.iData, aBitmapDesc.iDataSize); |
|
132 TInt err = regBmp->Draw(readStream, aRegionOfInterest); |
|
133 readStream.Close(); |
|
134 if (err != KErrNone) |
|
135 { |
|
136 #ifdef _DEBUG |
|
137 RDebug::Printf("Example Rasterizer Error: CExampleRasterizer::CRegisteredBitmap::Draw() returned %d", err); |
|
138 #endif // _DEBUG |
|
139 delete regBmp; |
|
140 return; |
|
141 } |
|
142 |
|
143 // Success |
|
144 iRegisteredBmps.AddLast(*regBmp); |
|
145 regBmp->iRefCount = 1; |
|
146 } |
|
147 |
|
148 /** Unregister an extended bitmap from this rasterizer. |
|
149 |
|
150 @see CFbsRasterizer::EndBitmap() |
|
151 @see BeginBitmap() |
|
152 */ |
|
153 void CExampleRasterizer::EndBitmap(TInt64 aBitmapId) |
|
154 { |
|
155 CRegisteredBitmap* regBmp = RegisteredBitmap(aBitmapId); |
|
156 if (regBmp) |
|
157 { |
|
158 if (--regBmp->iRefCount == 0) |
|
159 { |
|
160 // Put unregistered bitmap in the cache of recently used bitmaps if wholly pre-rendered |
|
161 // and there is an active scheduler to add the idle-time clean-up active object to |
|
162 if (regBmp->iWhole && CActiveScheduler::Current()) |
|
163 { |
|
164 if (!iIdle) |
|
165 { |
|
166 iIdle = CIdle::New(CActive::EPriorityIdle); |
|
167 if (!iIdle) |
|
168 { |
|
169 delete regBmp; |
|
170 return; |
|
171 } |
|
172 } |
|
173 regBmp->iLink.Deque(); |
|
174 iRecentBmps.AddFirst(*regBmp); |
|
175 iTotalRecentBmpSize += regBmp->iBufLength; |
|
176 // Delete the least recently used bitmaps if the maximum size of the cache is exceeded |
|
177 while (iTotalRecentBmpSize > KMaxRecentBmpCacheSize) |
|
178 { |
|
179 regBmp = iRecentBmps.Last(); |
|
180 iTotalRecentBmpSize -= regBmp->iBufLength; |
|
181 delete regBmp; |
|
182 } |
|
183 // If the cache is not empty make sure the idle-time clean-up active object is scheduled to run |
|
184 if (!iRecentBmps.IsEmpty() && !iIdle->IsActive()) |
|
185 { |
|
186 iIdle->Start(TCallBack(IdleFunction, this)); |
|
187 } |
|
188 } |
|
189 else |
|
190 { |
|
191 delete regBmp; |
|
192 } |
|
193 } |
|
194 } |
|
195 #ifdef _DEBUG |
|
196 else |
|
197 { |
|
198 RDebug::Printf("Example Rasterizer Error: CExampleRasterizer::EndBitmap() called for a bitmap that is not registered"); |
|
199 } |
|
200 #endif // _DEBUG |
|
201 } |
|
202 |
|
203 /** Return a scanline from the passed extended bitmap given its bitmap id. |
|
204 |
|
205 @see CFbsRasterizer::ScanLine() |
|
206 @see BeginBitmap() |
|
207 @see EndBitmap() |
|
208 */ |
|
209 const TUint32* CExampleRasterizer::ScanLine(TInt64 aBitmapId, const TPoint& aPixel, TInt aLength) |
|
210 { |
|
211 // Check that BeginBitmap() was called successfully and the passed bitmap was registered |
|
212 // with this rasterizer |
|
213 CRegisteredBitmap* regBmp = RegisteredBitmap(aBitmapId); |
|
214 if (regBmp) |
|
215 { |
|
216 // Parameter check |
|
217 if ((aPixel.iX < 0) || (aPixel.iX >= regBmp->iSizeInPixels.iWidth) |
|
218 || (aPixel.iY < 0) || (aPixel.iY >= regBmp->iSizeInPixels.iHeight) |
|
219 || (aLength > (regBmp->iSizeInPixels.iWidth - aPixel.iX))) // the requested length in pixels is greater than the declared width of the bitmap |
|
220 { |
|
221 #ifdef _DEBUG |
|
222 RDebug::Printf("Example Rasterizer Error: Invalid parameter passed to CExampleRasterizer::ScanLine()"); |
|
223 #endif // _DEBUG |
|
224 return NULL; |
|
225 } |
|
226 |
|
227 TInt scanLineLength = CFbsBitmap::ScanLineLength(regBmp->iSizeInPixels.iWidth, regBmp->iDispMode); |
|
228 return reinterpret_cast<TUint32*>(regBmp->Buffer() + (aPixel.iY * scanLineLength)); |
|
229 } |
|
230 #ifdef _DEBUG |
|
231 else |
|
232 { |
|
233 RDebug::Printf("Example Rasterizer Error: CExampleRasterizer::ScanLine() called for a bitmap that is not registered"); |
|
234 } |
|
235 #endif // _DEBUG |
|
236 |
|
237 return NULL; |
|
238 } |
|
239 |
|
240 /** Only MFbsRasterizerClearCache available, KErrExtensionNotSupported returned for all other cases. |
|
241 |
|
242 @see CFbsRasterizer::GetInterface() |
|
243 */ |
|
244 TInt CExampleRasterizer::GetInterface(TUid aInterfaceId, TAny*& aInterface) |
|
245 { |
|
246 aInterface = NULL; |
|
247 TInt err = KErrNone; |
|
248 |
|
249 switch (aInterfaceId.iUid) |
|
250 { |
|
251 case KUidFbsRasterizerClearCache: |
|
252 aInterface = static_cast<MFbsRasterizerClearCache*>(this); |
|
253 break; |
|
254 default: |
|
255 err = KErrExtensionNotSupported; |
|
256 break; |
|
257 } |
|
258 |
|
259 return err; |
|
260 } |
|
261 |
|
262 |
|
263 /** Gets a bitmap that has been registered with this rasterizer. |
|
264 |
|
265 @param aBitmapId The ID of the bitmap to check for. |
|
266 |
|
267 @return A pointer to the registered bitmap if found, NULL otherwise. |
|
268 */ |
|
269 CExampleRasterizer::CRegisteredBitmap* CExampleRasterizer::RegisteredBitmap(TInt64 aBitmapId) |
|
270 { |
|
271 TDblQueIter<CRegisteredBitmap> iter(iRegisteredBmps); |
|
272 while (CRegisteredBitmap* regBmp = iter++) |
|
273 { |
|
274 if (regBmp->iBitmapId == aBitmapId) |
|
275 { |
|
276 return regBmp; |
|
277 } |
|
278 } |
|
279 return NULL; |
|
280 } |
|
281 |
|
282 /** Gets a bitmap that has been recently used with this rasterizer. |
|
283 |
|
284 @param aBitmapId The ID of the bitmap to check for. |
|
285 |
|
286 @return A pointer to the recently used bitmap if found, NULL otherwise. |
|
287 */ |
|
288 CExampleRasterizer::CRegisteredBitmap* CExampleRasterizer::RecentBitmap(TInt64 aBitmapId) |
|
289 { |
|
290 TDblQueIter<CRegisteredBitmap> iter(iRecentBmps); |
|
291 while (CRegisteredBitmap* regBmp = iter++) |
|
292 { |
|
293 if (regBmp->iBitmapId == aBitmapId) |
|
294 { |
|
295 return regBmp; |
|
296 } |
|
297 } |
|
298 return NULL; |
|
299 } |
|
300 |
|
301 /** Releases the memory for all the recently rasterized extended bitmaps kept in the cache. |
|
302 This function is called by the idle-time active object. |
|
303 |
|
304 @param aSelf A pointer to the rasterizer object. |
|
305 |
|
306 @return Zero to indicate that this function needn't be automatically called again. |
|
307 */ |
|
308 TInt CExampleRasterizer::IdleFunction(TAny* aPtr) |
|
309 { |
|
310 CExampleRasterizer* self = static_cast<CExampleRasterizer*>(aPtr); |
|
311 while (!self->iRecentBmps.IsEmpty()) |
|
312 { |
|
313 delete self->iRecentBmps.First(); |
|
314 } |
|
315 self->iTotalRecentBmpSize = 0; |
|
316 return 0; |
|
317 } |
|
318 |
|
319 |
|
320 /** Constructor. |
|
321 */ |
|
322 CExampleRasterizer::CRegisteredBitmap::CRegisteredBitmap(TInt64 aBitmapId, |
|
323 const TBitmapDesc& aBitmapDesc, |
|
324 TInt aBufLength) |
|
325 : iBitmapId(aBitmapId), |
|
326 iSizeInPixels(aBitmapDesc.iSizeInPixels), |
|
327 iDispMode(aBitmapDesc.iDispMode), |
|
328 iDataType(aBitmapDesc.iDataType), |
|
329 iBufLength(aBufLength) |
|
330 {} |
|
331 |
|
332 /** Destructor. |
|
333 */ |
|
334 CExampleRasterizer::CRegisteredBitmap::~CRegisteredBitmap() |
|
335 { |
|
336 iLink.Deque(); |
|
337 } |
|
338 |
|
339 /** Rasterize a registered extended bitmap. The results are stored into the memory buffer embedded in this object. |
|
340 |
|
341 @param aReadStream A stream to read the proprietary data from. |
|
342 @param aRegionOfInterest The region within which scanline access requests will be made, if known. |
|
343 |
|
344 @return KErrNone on success, KErrNotSupported if the display mode is not supported, |
|
345 KErrEof if there is not enough data to read, KErrArgument if aRegionOfInterest is out of bounds. |
|
346 */ |
|
347 TInt CExampleRasterizer::CRegisteredBitmap::Draw(RMemReadStream& aReadStream, const TRegion* aRegionOfInterest) |
|
348 { |
|
349 if (aRegionOfInterest && !aRegionOfInterest->IsContainedBy(iSizeInPixels)) |
|
350 { |
|
351 return KErrArgument; |
|
352 } |
|
353 |
|
354 // Read the three flag colours and the horizontal stripe flag from the data |
|
355 TRgb colour1, colour2, colour3; |
|
356 TUint8 horizontalStripe; |
|
357 TRAPD(err, |
|
358 aReadStream >> colour1; |
|
359 aReadStream >> colour2; |
|
360 aReadStream >> colour3; |
|
361 aReadStream >> horizontalStripe; |
|
362 ); |
|
363 if (err != KErrNone) |
|
364 { |
|
365 return err; |
|
366 } |
|
367 TUint32 c1, c2, c3; |
|
368 TInt bpp; |
|
369 switch (iDispMode) |
|
370 { |
|
371 case EGray256: |
|
372 c1 = colour1.Gray256(); |
|
373 c2 = colour2.Gray256(); |
|
374 c3 = colour3.Gray256(); |
|
375 bpp = 1; |
|
376 break; |
|
377 case EColor64K: |
|
378 c1 = colour1.Color64K(); |
|
379 c2 = colour2.Color64K(); |
|
380 c3 = colour3.Color64K(); |
|
381 bpp = 2; |
|
382 break; |
|
383 case EColor16MU: |
|
384 c1 = colour1.Color16MU() | 0xFF000000; |
|
385 c2 = colour2.Color16MU() | 0xFF000000; |
|
386 c3 = colour3.Color16MU() | 0xFF000000; |
|
387 bpp = 4; |
|
388 break; |
|
389 case EColor16MAP: |
|
390 c1 = colour1.Color16MAP(); |
|
391 c2 = colour2.Color16MAP(); |
|
392 c3 = colour3.Color16MAP(); |
|
393 bpp = 4; |
|
394 break; |
|
395 default: |
|
396 return KErrNotSupported; |
|
397 } |
|
398 |
|
399 // If no region of interest is specified, rasterize the whole size of the bitmap |
|
400 // Otherwise rasterize only the rectangles in the region of interest |
|
401 // (Method takes no account of overlapping rectangles) |
|
402 TRect wholeRect(iSizeInPixels); |
|
403 TInt numRects; |
|
404 const TRect* rects; |
|
405 if (aRegionOfInterest) |
|
406 { |
|
407 numRects = aRegionOfInterest->Count(); |
|
408 rects = aRegionOfInterest->RectangleList(); |
|
409 // Pre-fill the flag with white so that areas outside the region of interest are white |
|
410 // (this is not necessary but has been added to allow use of this rasterizer in BitGDI testing) |
|
411 Mem::Fill(Buffer(), iBufLength, 0xFF); |
|
412 } |
|
413 else |
|
414 { |
|
415 // Set the only rect to be drawn to the whole size of the bitmap as no region of interest is specified |
|
416 numRects = 1; |
|
417 rects = &wholeRect; |
|
418 } |
|
419 |
|
420 // Get the scanline length we should use for this display mode as the scanlines we draw must be 32-bit aligned |
|
421 TInt scanLineLength = CFbsBitmap::ScanLineLength(iSizeInPixels.iWidth, iDispMode); |
|
422 |
|
423 if (horizontalStripe) |
|
424 { |
|
425 // Horizontal stripes |
|
426 TInt stripeHeight = iSizeInPixels.iHeight / 3; |
|
427 for (TInt r = 0; r < numRects; ++r) |
|
428 { |
|
429 for (TInt h = rects[r].iTl.iY; h < rects[r].iBr.iY; ++h) |
|
430 { |
|
431 for (TInt w = rects[r].iTl.iX; w < rects[r].iBr.iX; ++w) |
|
432 { |
|
433 if (h < stripeHeight) |
|
434 { |
|
435 Mem::Copy(Buffer() + (w * bpp) + (h * scanLineLength), &c1, bpp); // top |
|
436 } |
|
437 else if (h < iSizeInPixels.iHeight - stripeHeight) |
|
438 { |
|
439 Mem::Copy(Buffer() + (w * bpp) + (h * scanLineLength), &c2, bpp); // middle |
|
440 } |
|
441 else |
|
442 { |
|
443 Mem::Copy(Buffer() + (w * bpp) + (h * scanLineLength), &c3, bpp); // bottom |
|
444 } |
|
445 } |
|
446 } |
|
447 } |
|
448 } |
|
449 else |
|
450 { |
|
451 // Vertical stripes |
|
452 TInt stripeWidth = iSizeInPixels.iWidth / 3; |
|
453 for (TInt r = 0; r < numRects; ++r) |
|
454 { |
|
455 for (TInt h = rects[r].iTl.iY; h < rects[r].iBr.iY; ++h) |
|
456 { |
|
457 for (TInt w = rects[r].iTl.iX; w < rects[r].iBr.iX; ++w) |
|
458 { |
|
459 if (w < stripeWidth) |
|
460 { |
|
461 Mem::Copy(Buffer() + (w * bpp) + (h * scanLineLength), &c1, bpp); // left |
|
462 } |
|
463 else if (w < iSizeInPixels.iWidth - stripeWidth) |
|
464 { |
|
465 Mem::Copy(Buffer() + (w * bpp) + (h * scanLineLength), &c2, bpp); // middle |
|
466 } |
|
467 else |
|
468 { |
|
469 Mem::Copy(Buffer() + (w * bpp) + (h * scanLineLength), &c3, bpp); // right |
|
470 } |
|
471 } |
|
472 } |
|
473 } |
|
474 } |
|
475 |
|
476 iWhole = (numRects == 1 && rects[0] == wholeRect); |
|
477 return KErrNone; |
|
478 } |
|
479 |
|
480 /** Gets a pointer to the pre-rendered buffer for this registered bitmap. |
|
481 */ |
|
482 TUint8* CExampleRasterizer::CRegisteredBitmap::Buffer() |
|
483 { |
|
484 // Adding one to "this" is the same as adding sizeof(*this) to the address of this object |
|
485 // The result points to the pre-rendered buffer, located right after the instance variables |
|
486 return reinterpret_cast<TUint8*>(this + 1); |
|
487 } |
|
488 |
|
489 /** Implementation of MFbsRasterizerClearCache::ClearCache() to allow test code to |
|
490 clear the cache of recently used extended bitmaps. |
|
491 */ |
|
492 void CExampleRasterizer::ClearCache() |
|
493 { |
|
494 while (!iRecentBmps.IsEmpty()) |
|
495 { |
|
496 delete iRecentBmps.First(); |
|
497 } |
|
498 iTotalRecentBmpSize = 0; |
|
499 if (iIdle && iIdle->IsActive()) |
|
500 { |
|
501 iIdle->Cancel(); |
|
502 } |
|
503 } |