|
1 /* |
|
2 * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: |
|
15 * |
|
16 */ |
|
17 |
|
18 #include <e32cmn.h> |
|
19 #include <j2me/jdebug.h> |
|
20 |
|
21 #include "CMIDScaler.h" |
|
22 |
|
23 #define REL_MODE |
|
24 |
|
25 #ifdef REL_MODE |
|
26 #include "CMIDMenuHandler.h" // For TlsStruct |
|
27 #else |
|
28 struct TlsStruct |
|
29 { |
|
30 CMIDScaler* iScaler; |
|
31 }; |
|
32 |
|
33 TlsStruct* tls = NULL; |
|
34 #endif |
|
35 |
|
36 /* |
|
37 * Internal definitions. |
|
38 */ |
|
39 #define INT_PRECISION 12 // !Max 12! |
|
40 #define INT_FULL_PXL (1<<INT_PRECISION) |
|
41 #define INT_HALF_PXL (1<<(INT_PRECISION-1)) |
|
42 |
|
43 /* |
|
44 * Internal macros. |
|
45 */ |
|
46 #define SET_SWI_BIT(x) ((x) | 0x8000) |
|
47 #define CLR_SWI_BIT(x) ((x) & 0x7fff) |
|
48 #define TST_SWI_BIT(x) (((x) & 0x8000) != 0) |
|
49 |
|
50 #if !defined (__WINS__) && !defined (__WINSCW__) |
|
51 #define ARMV5_OPTIMIZATIONS |
|
52 #endif |
|
53 |
|
54 |
|
55 #if defined(ARMV5_OPTIMIZATIONS) |
|
56 void InterpolateOne2Four_kernel(const TUint32* in, |
|
57 TUint32* out, |
|
58 TUint32 width, |
|
59 TUint32 height, |
|
60 TUint32 offset); |
|
61 #endif |
|
62 // --------------------------------------------------------------------------- |
|
63 // |
|
64 // --------------------------------------------------------------------------- |
|
65 // |
|
66 CMIDScaler* CMIDScaler::NewL() |
|
67 { |
|
68 // For Some reason codescanner sets error "error: leave: high: canpanic: |
|
69 // leaving function called in non-leaving function" even though this is |
|
70 // a leaving function! |
|
71 |
|
72 CMIDScaler* sca = new(ELeave) CMIDScaler(); // codescanner::leave |
|
73 CleanupStack::PushL(sca); // codescanner::leave |
|
74 sca->ConstructL(); // codescanner::leave |
|
75 CleanupStack::Pop(sca); |
|
76 return sca; |
|
77 } |
|
78 |
|
79 // --------------------------------------------------------------------------- |
|
80 // To delete this object. |
|
81 // |
|
82 // @Preconditions The following conditions must be true prior the calling this |
|
83 // method; otherwise, its operation is undefined. |
|
84 // - None |
|
85 // |
|
86 // @Postconditions The following conditions are true immediately after |
|
87 // returning from this method, if the bitmap is processed. |
|
88 // - None |
|
89 // |
|
90 // @param None. |
|
91 // @return None. |
|
92 // @exception None. |
|
93 // |
|
94 // --------------------------------------------------------------------------- |
|
95 // |
|
96 CMIDScaler::~CMIDScaler() |
|
97 { |
|
98 iLock.Close(); |
|
99 delete iBmap; |
|
100 } |
|
101 |
|
102 // --------------------------------------------------------------------------- |
|
103 // To interpolate an input image. |
|
104 // |
|
105 // @Definition This method interpolates the input bitmap. It returns the |
|
106 // reference to the interpolated bitmap or NULL, if it is not able to |
|
107 // process the input bitmap for some reason. The ownership of the output |
|
108 // bitmap is not change. |
|
109 // |
|
110 // This method is synchronized. |
|
111 // |
|
112 // @Preconditions The following conditions must be true prior the calling this |
|
113 // method; otherwise, its operation is undefined. |
|
114 // - None |
|
115 // |
|
116 // @Postconditions The following conditions are true immediately after |
|
117 // returning from this method, if the bitmap is processed. |
|
118 // - aImgIn is untouched. |
|
119 // - iBmap.size == outWidth*outHeight. |
|
120 // - iBmap.mode == aMode. |
|
121 // |
|
122 // @param aMode - A display mode. |
|
123 // @param aImgIn - A pointer to the input image. |
|
124 // @param aWidth - A width of an input image. |
|
125 // @param aHeight - A height of an input image. |
|
126 // @param aOffset - A offset of an input image: line = offset + width. |
|
127 // @param aOutWidth - A width of an output image. |
|
128 // @param aOutWeight - A height of an output image. |
|
129 // @return Reference to the interpolated bitmap, or NULL. |
|
130 // @exception None. |
|
131 // |
|
132 // --------------------------------------------------------------------------- |
|
133 // |
|
134 CFbsBitmap* CMIDScaler::Process(TDisplayMode aMode, |
|
135 const TUint32* aImgIn, |
|
136 TUint aWidth, |
|
137 TUint aHeight, |
|
138 TUint aOffset, |
|
139 TUint aOutWidth, |
|
140 TUint aOutHeight) |
|
141 { |
|
142 // Debug macros. |
|
143 //__UHEAP_MARK; |
|
144 |
|
145 DEBUG_INT("CMIDScaler::Process - mod: %d", aMode); |
|
146 DEBUG_INT("CMIDScaler::Process - wid: %d", aWidth); |
|
147 DEBUG_INT("CMIDScaler::Process - hei: %d", aHeight); |
|
148 DEBUG_INT("CMIDScaler::Process - off: %d", aOffset); |
|
149 DEBUG_INT("CMIDScaler::Process - owi: %d", aOutWidth); |
|
150 DEBUG_INT("CMIDScaler::Process - ohe: %d", aOutHeight); |
|
151 DEBUG_INT("CMIDScaler::Process - maX: %d", iMaxX); |
|
152 DEBUG_INT("CMIDScaler::Process - maY: %d", iMaxY); |
|
153 DEBUG_INT("CMIDScaler::Process - inX: %d", iIntX); |
|
154 DEBUG_INT("CMIDScaler::Process - inY: %d", iIntY); |
|
155 |
|
156 CFbsBitmap* bmap = NULL; |
|
157 |
|
158 // Wait for the access to the lock object. |
|
159 iLock.Wait(); |
|
160 |
|
161 if ((aMode == EColor16MU || aMode == EColor16MA) && |
|
162 aWidth >= 2 && |
|
163 aWidth <= aOutWidth && |
|
164 aWidth <= iMaxX && |
|
165 aHeight >= 2 && |
|
166 aHeight <= aOutHeight && |
|
167 aHeight <= iMaxY && |
|
168 aOutWidth <= iIntX && |
|
169 aOutHeight <= iIntY) |
|
170 { |
|
171 TInt err = KErrNone; |
|
172 |
|
173 // If this is the first call of this method, create new bitmap. |
|
174 if (iIsBm == EFalse) |
|
175 { |
|
176 iBmap = new CFbsBitmap; |
|
177 if (iBmap) |
|
178 { |
|
179 err = iBmap->Create(TSize(aOutWidth, aOutHeight), aMode); |
|
180 if (err != KErrNone) |
|
181 { |
|
182 delete iBmap; |
|
183 iBmap = NULL; |
|
184 } |
|
185 else |
|
186 { |
|
187 iIsBm = ETrue; |
|
188 } |
|
189 } |
|
190 } |
|
191 |
|
192 // Do interpolation. |
|
193 if (iIsBm) |
|
194 { |
|
195 if (aOutWidth == 2*aWidth && aOutHeight == 2*aHeight) |
|
196 { |
|
197 InterpolateOne2Four(aImgIn, aWidth, aHeight, aOffset, aMode); |
|
198 } |
|
199 else |
|
200 { |
|
201 Interpolate(aImgIn, aWidth, aHeight, aOffset, aOutWidth, aOutHeight, aMode); |
|
202 } |
|
203 bmap = iBmap; |
|
204 } |
|
205 } |
|
206 |
|
207 // Release the lock object. |
|
208 iLock.Signal(); |
|
209 |
|
210 // Debug macros. |
|
211 //__UHEAP_MARKEND; |
|
212 |
|
213 return bmap; |
|
214 } |
|
215 |
|
216 // --------------------------------------------------------------------------- |
|
217 // To do 1st phase construction for this object. |
|
218 // |
|
219 // @Preconditions The following conditions must be true prior the calling this |
|
220 // method; otherwise, its operation is undefined. |
|
221 // - None |
|
222 // |
|
223 // @Postconditions The following conditions are true immediately after |
|
224 // returning from this method, if the bitmap is processed. |
|
225 // - None |
|
226 // |
|
227 // @param None. |
|
228 // @return None. |
|
229 // @exception None. |
|
230 // |
|
231 // --------------------------------------------------------------------------- |
|
232 // |
|
233 CMIDScaler::CMIDScaler() |
|
234 { |
|
235 iBpp = 4; |
|
236 iRefC = 0; |
|
237 iMode = EColor16MU; |
|
238 iMaxX = iIntX = 640; |
|
239 iMaxY = iIntY = 640; |
|
240 iIsBm = EFalse; |
|
241 iLock.CreateLocal(); |
|
242 } |
|
243 |
|
244 // --------------------------------------------------------------------------- |
|
245 // To do 2nd phase construction for this object. |
|
246 // |
|
247 // @Preconditions The following conditions must be true prior the calling this |
|
248 // method; otherwise, its operation is undefined. |
|
249 // - None |
|
250 // |
|
251 // @Postconditions The following conditions are true immediately after |
|
252 // returning from this method, if the bitmap is processed. |
|
253 // - None |
|
254 // |
|
255 // @param None. |
|
256 // @return None. |
|
257 // @exception If the method is not able to allocate necessary buffers. |
|
258 // |
|
259 // --------------------------------------------------------------------------- |
|
260 // |
|
261 void CMIDScaler::ConstructL() |
|
262 { |
|
263 } |
|
264 |
|
265 |
|
266 // --------------------------------------------------------------------------- |
|
267 // To do differential interpolation for an input image. |
|
268 // |
|
269 // @Definition The differential interpolation is based on the equation |
|
270 // |
|
271 // o = | a, if l = dist(o,a) |
|
272 // | b, if l = dist(o,b) |
|
273 // | c, if l = dist(o,c) |
|
274 // | d, if l = dist(o,d) |
|
275 // |
|
276 // where o is an output pixel, |
|
277 // |
|
278 // l = min(dist(o,a), dist(o,b), dist(o,c), dist(o,d)) |
|
279 // |
|
280 // and dist is a component metric, i.e., dist(x,y) = |x1-y1| + |x2-y2|. |
|
281 // |
|
282 // Lets assume that we have to interpolate one output pixel o. It has always |
|
283 // four surrounding input pixels orientated as depicted in Figure 1: |
|
284 // |
|
285 // a<------x>+<------->b |
|
286 // | : : | |
|
287 // | : : | |
|
288 // | A1 : : A2 | |
|
289 // | : : | |
|
290 // | : : | |
|
291 // +------:-+--------+ |
|
292 // | : : | |
|
293 // y......o : | |
|
294 // | A3 : A4 | |
|
295 // | : | |
|
296 // | : | |
|
297 // c<------->+<------->d |
|
298 // |
|
299 // Figure 1. An output pixel o is always surrounded by four input pixels, a, b, |
|
300 // c and d. All pixels in specific area will have same value, e.g., |
|
301 // pixel o in area A3 will have same value as c. |
|
302 // |
|
303 // It is obvious that c is the nearest pixel to o in Figure 1. Therefore o will |
|
304 // have value of c. |
|
305 // |
|
306 // The basic problem of interpolation is how the last pixels are interpolated. |
|
307 // Here the last row and column are replicated (look Figure 2), so the last |
|
308 // pixels are interpolated same way as the others. |
|
309 // |
|
310 // : : : : : : : : |
|
311 // +----+----+ ... +----+----+..... |
|
312 // | v0 | v1 | ... |vN-2|vN-1|vN-1: |
|
313 // +----+----+ ... +----+----+..... |
|
314 // : v0 : v1 : ... :vN-2:vN-1:vN-1:<- Last pseudo row |
|
315 // ........... ... ................ |
|
316 // | |
|
317 // +- Last pseudo column |
|
318 // |
|
319 // Figure 2. Pseudo pixels are added in order to get simple implementation. |
|
320 // |
|
321 // @Preconditions The following conditions must be true prior the calling this |
|
322 // method; otherwise, its operation is undefined. |
|
323 // - 2 <= width <= maxX |
|
324 // - 2 <= height |
|
325 // - width <= outWidth |
|
326 // - height <= outHeight |
|
327 // - outWidth <= intX |
|
328 // - outHeight <= intY |
|
329 // - log2(INT_FULL_PXL*width) <= 32 |
|
330 // - log2(INT_FULL_PXL*height) <= 32 |
|
331 // - aMode == EColor16MU || EColor16MA |
|
332 // - IsCompressedInRAM == EFalse |
|
333 // |
|
334 // @Postconditions The following conditions are true immediately after |
|
335 // returning from this method. |
|
336 // - iBmap.size == outWidth*outHeight. |
|
337 // - iBmap.mode == aMode. |
|
338 // |
|
339 // @param imgIn - A pointer to the input image. |
|
340 // @param width - A width of an input image. |
|
341 // @param height - A height of an input image. |
|
342 // @param offset - A offset of an input image: line = offset + width. |
|
343 // @param outWidth - A width of an output image. |
|
344 // @param outWeight - A height of an output image. |
|
345 // @param aMode - A display mode. |
|
346 // @return None. |
|
347 // @exception None. |
|
348 // |
|
349 // @Note This method has originally been a bilinear interpolation. Hence the |
|
350 // element of the weight tables has 16 bits, but here only two of them are |
|
351 // used. |
|
352 // |
|
353 // --------------------------------------------------------------------------- |
|
354 // |
|
355 void CMIDScaler::Interpolate(const TUint32* aImgIn, |
|
356 TUint width, |
|
357 TUint height, |
|
358 TUint offset, |
|
359 TUint outWidth, |
|
360 TUint outHeight, |
|
361 TDisplayMode aMode) |
|
362 { |
|
363 |
|
364 TUint32 stepX, stepY, roundX, roundY, j, k; |
|
365 const TUint32 *src; |
|
366 TUint32 *dst; |
|
367 |
|
368 |
|
369 if (aMode != iBmap->DisplayMode()) |
|
370 iBmap->SetDisplayMode(aMode); |
|
371 if ((iBmap->SizeInPixels().iWidth != outWidth) |
|
372 || (iBmap->SizeInPixels().iHeight != outHeight)) |
|
373 iBmap->Resize(TSize(outWidth, outHeight)); |
|
374 |
|
375 stepX = (TUint32)((16384*width)/outWidth); |
|
376 stepY = (TUint32)((16384*height)/outHeight); |
|
377 roundX = stepX>>1; |
|
378 roundY = stepY>>1; |
|
379 iBmap->LockHeap(); |
|
380 dst = iBmap->DataAddress(); |
|
381 |
|
382 for (j = 0; j < outHeight; j++) |
|
383 { |
|
384 // Interpolate one scanline. |
|
385 src = &aImgIn[(width+offset)*((stepY*j + roundY)>>14)]; |
|
386 for (k = roundX; k < outWidth*stepX + roundX; k+=stepX) |
|
387 { |
|
388 *dst++ = src[k>>14]; |
|
389 } |
|
390 } |
|
391 iBmap->UnlockHeap(); |
|
392 |
|
393 } |
|
394 |
|
395 // --------------------------------------------------------------------------- |
|
396 // To double scale the bitmap. |
|
397 // |
|
398 // @Preconditions The following conditions must be true prior to calling |
|
399 // this method; otherwise, its operation is undefined. |
|
400 // - width(src) > 0 |
|
401 // - height(src) > 0 |
|
402 // - width(dst) == 2*width(src) |
|
403 // - height(dst) == 2*height(src) |
|
404 // - IsCompressedInRAM == EFalse |
|
405 // - DisplayMode() == EColor16MU || EColor16MA |
|
406 // |
|
407 // @Postconditions The following condition is true immediately after |
|
408 // returning from this method. |
|
409 // - iBmap.size == outWidth*outHeight. |
|
410 // - iBmap.mode == aMode. |
|
411 // |
|
412 // @param aImgIn - A pointer to the input image. |
|
413 // @param aWidth - A width of an input image. |
|
414 // @param aHeight - A height of an input image. |
|
415 // @param aOffset - A offset of an input image: line = offset + width. |
|
416 // @param aMode - A display mode. |
|
417 // @return None. |
|
418 // @exception None. |
|
419 // --------------------------------------------------------------------------- |
|
420 // |
|
421 void CMIDScaler::InterpolateOne2Four(const TUint32* aImgIn, |
|
422 TUint aWidth, |
|
423 TUint aHeight, |
|
424 TUint aOffset, |
|
425 TDisplayMode aMode) |
|
426 { |
|
427 if (aMode != iBmap->DisplayMode()) |
|
428 iBmap->SetDisplayMode(aMode); |
|
429 if ((iBmap->SizeInPixels().iWidth != 2*aWidth) |
|
430 || (iBmap->SizeInPixels().iHeight != 2*aHeight)) |
|
431 iBmap->Resize(TSize(2*aWidth, 2*aHeight)); |
|
432 |
|
433 iBmap->LockHeap(); |
|
434 TUint32* tmp1 = iBmap->DataAddress(); |
|
435 |
|
436 // Do double scaling. |
|
437 #if defined(ARMV5_OPTIMIZATIONS) |
|
438 InterpolateOne2Four_kernel(aImgIn, tmp1, aWidth, aHeight, aOffset); |
|
439 #else |
|
440 // Initialize variables. |
|
441 TInt32 x = 0; |
|
442 TInt32 y = 0; |
|
443 TInt32 i = 0; |
|
444 TUint32 pxl = 0; |
|
445 const TUint32* src1 = NULL; |
|
446 TUint32* dst1 = NULL; |
|
447 TUint32* dst2 = NULL; |
|
448 |
|
449 for (y = 0; y < aHeight; y++) |
|
450 { |
|
451 i = (aWidth + aOffset)*y; |
|
452 |
|
453 src1 = aImgIn; |
|
454 dst1 = dst2 = tmp1; |
|
455 src1 = &src1[i]; |
|
456 dst1 = &dst1[2*aWidth*2*y]; |
|
457 dst2 = &dst2[2*aWidth*(2*y+1)]; |
|
458 |
|
459 // Copy one scanline. |
|
460 for (x = 0; x < aWidth; x++) |
|
461 { |
|
462 pxl = *src1++; |
|
463 *dst1++ = pxl; |
|
464 *dst1++ = pxl; |
|
465 *dst2++ = pxl; |
|
466 *dst2++ = pxl; |
|
467 } |
|
468 } |
|
469 #endif |
|
470 iBmap->UnlockHeap(); |
|
471 |
|
472 } |
|
473 |
|
474 |
|
475 #if defined(ARMV5_OPTIMIZATIONS) |
|
476 __asm void InterpolateOne2Four_kernel(const TUint32* in, |
|
477 TUint32* out, |
|
478 TUint32 width, |
|
479 TUint32 height, |
|
480 TUint32 offset) |
|
481 { |
|
482 // r0 = in |
|
483 // r1 = out |
|
484 // r2 = width |
|
485 // r3 = height |
|
486 // sp[0] = offset |
|
487 |
|
488 CODE32 |
|
489 |
|
490 CMP r2, #0 |
|
491 BXEQ lr |
|
492 CMP r3, #0 |
|
493 BXEQ lr |
|
494 |
|
495 STMFD sp!, {r4-r12, lr} |
|
496 |
|
497 MOV r12, r2 // width |
|
498 ADD r14, r1, r2, LSL #3 // &out[2*width] |
|
499 |
|
500 CMIDScaler_InterpolateOne2Four_kernel_outerLoop |
|
501 MOVS r2, r12, ASR #2 // width/4 = number of 4x32 bit reads |
|
502 |
|
503 CMIDScaler_InterpolateOne2Four_kernel_innerLoop |
|
504 // read the 4x32bit-aligned input and interpolate |
|
505 LDMIANE r0!, {r4, r6, r8, r10} |
|
506 MOVNE r5, r4 |
|
507 MOVNE r7, r6 |
|
508 MOVNE r9, r8 |
|
509 MOVNE r11, r10 |
|
510 STMIANE r1!, {r4-r11} |
|
511 STMIANE r14!, {r4-r11} |
|
512 SUBSNE r2, #1 |
|
513 BNE CMIDScaler_InterpolateOne2Four_kernel_innerLoop |
|
514 |
|
515 MOV r2, r12, ASR #2 |
|
516 SUBS r2, r12, r2, LSL #2 // number of unaligned 32-bit reads |
|
517 |
|
518 // read the unaligned tail and interpolate |
|
519 CMIDScaler_InterpolateOne2Four_kernel_tailLoop |
|
520 |
|
521 LDRNE r6, [r0], #4 |
|
522 STRNE r6, [r1], #4 |
|
523 STRNE r6, [r1], #4 |
|
524 STRNE r6, [r14], #4 |
|
525 STRNE r6, [r14], #4 |
|
526 SUBSNE r2, #1 |
|
527 BNE CMIDScaler_InterpolateOne2Four_kernel_tailLoop |
|
528 |
|
529 // update pointers to the next line |
|
530 LDR r4, [sp, #(10*4)] |
|
531 SUBS r3, #1 |
|
532 MOV r1, r14 |
|
533 ADD r14, r1, r12, LSL #3 |
|
534 ADD r0, r0, r4, LSL #2 |
|
535 BNE CMIDScaler_InterpolateOne2Four_kernel_outerLoop |
|
536 |
|
537 LDMFD sp!, {r4-r12, lr} |
|
538 BX lr |
|
539 } |
|
540 #endif |