|
1 // Copyright (c) 2005-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 /** @file |
|
17 @internalComponent */ |
|
18 #include <bitmaptransforms.h> |
|
19 #include <icl/imagedisplayplugin.h> |
|
20 #include "MiscUtils.h" |
|
21 |
|
22 #include "ImagePostprocess.h" |
|
23 |
|
24 /*static*/ |
|
25 CAsyncTransformer* CAsyncTransformer::NewL(MPostProcessObserver& aObserver,CTransformerSharedData& aSingleton, |
|
26 const TSize& aDestSize) |
|
27 { |
|
28 return new (ELeave) CAsyncTransformer(aObserver, aSingleton, aDestSize); |
|
29 } |
|
30 |
|
31 CAsyncTransformer::CAsyncTransformer(MPostProcessObserver& aObserver, CTransformerSharedData& aSingleton, const TSize& aDestSize): |
|
32 CActive(EPriorityNormal), |
|
33 iObserver(aObserver), |
|
34 iSingleton(&aSingleton), |
|
35 iDestSize(aDestSize), |
|
36 iScaleQuality(CBitmapScaler::EMinimumQuality) |
|
37 |
|
38 { |
|
39 iSingleton->AddRef(); |
|
40 CActiveScheduler::Add(this); |
|
41 } |
|
42 |
|
43 CAsyncTransformer::~CAsyncTransformer() |
|
44 { |
|
45 Cleanup(); |
|
46 iSingleton->Release(); |
|
47 iSingleton = NULL; |
|
48 delete iScaleDest; |
|
49 delete iTransformDest; |
|
50 } |
|
51 |
|
52 TInt CAsyncTransformer::RunError(TInt aError) |
|
53 { |
|
54 iResultStatus = aError; |
|
55 iObserver.OnTransformDone(aError); |
|
56 return KErrNone; |
|
57 } |
|
58 |
|
59 TInt CAsyncTransformer::NextTransform(TUint& aTransFormTodo1) |
|
60 { |
|
61 if ((aTransFormTodo1&CImageDisplay::EOptionRotateCw90)==CImageDisplay::EOptionRotateCw90) |
|
62 { |
|
63 aTransFormTodo1 ^= CImageDisplay::EOptionRotateCw90; |
|
64 return CBitmapRotator::ERotation90DegreesClockwise; |
|
65 } |
|
66 |
|
67 if ((aTransFormTodo1&CImageDisplay::EOptionRotateCw180)==CImageDisplay::EOptionRotateCw180) |
|
68 { |
|
69 aTransFormTodo1 ^= CImageDisplay::EOptionRotateCw180; |
|
70 return CBitmapRotator::ERotation180DegreesClockwise; |
|
71 } |
|
72 |
|
73 if ((aTransFormTodo1&CImageDisplay::EOptionRotateCw270)==CImageDisplay::EOptionRotateCw270) |
|
74 { |
|
75 aTransFormTodo1 ^= CImageDisplay::EOptionRotateCw270; |
|
76 return CBitmapRotator::ERotation270DegreesClockwise; |
|
77 } |
|
78 |
|
79 if ((aTransFormTodo1&CImageDisplay::EOptionMirrorVertical)==CImageDisplay::EOptionMirrorVertical) |
|
80 { |
|
81 aTransFormTodo1 ^= CImageDisplay::EOptionMirrorVertical; |
|
82 return CBitmapRotator::EMirrorVerticalAxis; |
|
83 } |
|
84 |
|
85 if ((aTransFormTodo1&CImageDisplay::EOptionMirrorHorizontal)==CImageDisplay::EOptionMirrorHorizontal) |
|
86 { |
|
87 aTransFormTodo1 ^= CImageDisplay::EOptionMirrorHorizontal; |
|
88 return CBitmapRotator::EMirrorHorizontalAxis; |
|
89 } |
|
90 |
|
91 ASSERT(EFalse); |
|
92 return -1; |
|
93 } |
|
94 |
|
95 void CAsyncTransformer::RunL() |
|
96 { |
|
97 iResultStatus = iStatus.Int(); |
|
98 User::LeaveIfError( iStatus.Int() ); |
|
99 |
|
100 switch (iState) |
|
101 { |
|
102 //coverity[unterminated_case] |
|
103 case EStart: |
|
104 // go further |
|
105 CreateDestBitmapsL(); |
|
106 //coverity[fallthrough] |
|
107 case EClip: |
|
108 { |
|
109 if (iSingleton->ClippingSet()) |
|
110 { |
|
111 DeletePreTranformBmps(); |
|
112 DoClipL(iCurrentSource, iClippingDest); |
|
113 iCurrentSource = iClippingDest; |
|
114 iState=ETransform; |
|
115 RunAgain(); |
|
116 break; |
|
117 } |
|
118 } // if no clipping just go further |
|
119 case ETransform: |
|
120 { |
|
121 iState = ETransform; |
|
122 if (iSingleton->TransformOptions()==0) |
|
123 { |
|
124 iState = EScale; |
|
125 RunAgain(); |
|
126 break; |
|
127 } |
|
128 if (iTransformTodo==0) |
|
129 { |
|
130 iState = ETransformDone; |
|
131 } |
|
132 else |
|
133 { |
|
134 CBitmapRotator::TRotationAngle transfromInstr=CBitmapRotator::TRotationAngle(NextTransform(iTransformTodo)); |
|
135 if (iCurrentSource != iTransformDest) |
|
136 { |
|
137 iSingleton->RotatorL().Rotate(&iStatus, *iCurrentSource, *iTransformDest, transfromInstr); |
|
138 } |
|
139 else |
|
140 { |
|
141 iSingleton->RotatorL().Rotate(&iStatus, *iTransformDest, transfromInstr); |
|
142 } |
|
143 |
|
144 iCurrentSource = iTransformDest; |
|
145 SetActive(); |
|
146 break; |
|
147 } |
|
148 } |
|
149 case ETransformDone: |
|
150 { |
|
151 iCurrentSource = iTransformDest; |
|
152 } // and go to scale |
|
153 case EScale: |
|
154 iState = EScale; |
|
155 if (iClippingDest!=iCurrentSource) |
|
156 { |
|
157 DeletePreTranformBmps(); |
|
158 } |
|
159 if (iScaleNeeded) |
|
160 { |
|
161 CBitmapScaler& scaler=iSingleton->ScalerL(); |
|
162 User::LeaveIfError( scaler.SetQualityAlgorithm( CBitmapScaler::TQualityAlgorithm(iScaleQuality)) ); |
|
163 scaler.Scale(&iStatus, *iCurrentSource, *iScaleDest, EFalse); |
|
164 // the EFalse is used because the Scaler uses an algorithm that is different for one |
|
165 // that is used by CImageDecoder to calculate scaled sizes, so sizes sometime differ. |
|
166 // there is no workaround for now.... |
|
167 iCurrentSource = iScaleDest; |
|
168 SetActive(); |
|
169 iState = EDone; |
|
170 break; |
|
171 } |
|
172 case EDone: |
|
173 iState = EDone; |
|
174 if (iClippingDest!=iCurrentSource) |
|
175 { |
|
176 DeletePreTranformBmps(); |
|
177 } |
|
178 if (iTransformDest!=iCurrentSource) |
|
179 { |
|
180 delete iTransformDest; |
|
181 iTransformDest = NULL; |
|
182 } |
|
183 iObserver.OnTransformDone(iResultStatus); |
|
184 break; |
|
185 default: |
|
186 ASSERT(EFalse); |
|
187 } |
|
188 } |
|
189 |
|
190 void CAsyncTransformer::Cleanup() |
|
191 { |
|
192 iSingleton->Cleanup(); |
|
193 DeletePreTranformBmps(); |
|
194 } |
|
195 |
|
196 void CAsyncTransformer::DoCancel() |
|
197 { |
|
198 Cleanup(); |
|
199 iStatus = KErrCancel; |
|
200 } |
|
201 |
|
202 void CAsyncTransformer::CreateDestBitmapsL() |
|
203 { |
|
204 delete iScaleDest; iScaleDest = NULL; |
|
205 |
|
206 iScaleDest = new (ELeave) CFbsBitmap(); |
|
207 User::LeaveIfError(iScaleDest->Create(iDestSize, iCurrentSource->DisplayMode()) ); |
|
208 |
|
209 delete iTransformDest; iTransformDest= NULL; |
|
210 |
|
211 iTransformDest = new (ELeave) CFbsBitmap(); |
|
212 User::LeaveIfError(iTransformDest->Create(TSize(1,1), iCurrentSource->DisplayMode()) ); |
|
213 } |
|
214 |
|
215 void CAsyncTransformer::DeletePreTranformBmps() |
|
216 { |
|
217 delete iClippingDest; |
|
218 iClippingDest = NULL; |
|
219 } |
|
220 |
|
221 void CAsyncTransformer::DoClipL(CFbsBitmap* aSrc, CFbsBitmap*& aDest) |
|
222 { |
|
223 ASSERT(aDest==NULL); |
|
224 aDest = new (ELeave) CFbsBitmap(); |
|
225 User::LeaveIfError( aDest->Create(iTrueClipRect.Size(), aSrc->DisplayMode()) ); |
|
226 |
|
227 CFbsBitmapDevice* device=CFbsBitmapDevice::NewL(aDest); |
|
228 CleanupStack::PushL(device); |
|
229 CFbsBitGc* gc=CFbsBitGc::NewL(); |
|
230 CleanupStack::PushL(gc); |
|
231 gc->Activate(device); |
|
232 gc->BitBlt(TPoint(0,0), aSrc, iTrueClipRect); |
|
233 CleanupStack::PopAndDestroy(2,device); |
|
234 } |
|
235 |
|
236 void CAsyncTransformer::Transform(CFbsBitmap* aImage, TBool aMantainAspect) |
|
237 { |
|
238 ASSERT(!IsActive()); |
|
239 |
|
240 iImgSource = iCurrentSource = aImage; |
|
241 iKeepAspect = aMantainAspect; |
|
242 |
|
243 const TSize srcSize(aImage->SizeInPixels()); |
|
244 |
|
245 iTrueClipRect = TRect(TPoint(0,0), srcSize.AsPoint()); |
|
246 TSize clipRectSize(srcSize); |
|
247 if (iSingleton->ClippingSet()) |
|
248 { |
|
249 const TRect& clipRect=iSingleton->ClipRect(); |
|
250 iTrueClipRect.iTl.iX=MulDiv(clipRect.iTl.iX, srcSize.iWidth, iSingleton->TrueSrcSize().iWidth); |
|
251 iTrueClipRect.iTl.iY=MulDiv(clipRect.iTl.iY, srcSize.iHeight,iSingleton->TrueSrcSize().iHeight); |
|
252 iTrueClipRect.SetWidth(MulDiv(clipRect.Width(), srcSize.iWidth, iSingleton->TrueSrcSize().iWidth)); |
|
253 iTrueClipRect.SetHeight(MulDiv(clipRect.Height(),srcSize.iHeight, iSingleton->TrueSrcSize().iHeight)); |
|
254 clipRectSize=ScaleSize(srcSize, iSingleton->TrueSrcSize(), clipRect.Size()); |
|
255 } |
|
256 RotateSize(clipRectSize, iSingleton->TransformOptions()); |
|
257 const TInt KMaxDelta=Min(7, Max(0, Max(iDestSize.iWidth / clipRectSize.iWidth, iDestSize.iHeight / clipRectSize.iHeight)-1 )); |
|
258 // apply some treshold to size comparison because of decoder rounding algorithm |
|
259 iScaleNeeded = (Abs(iDestSize.iWidth-clipRectSize.iWidth)>KMaxDelta || Abs(iDestSize.iHeight-clipRectSize.iHeight)>KMaxDelta); |
|
260 Restart(); |
|
261 } |
|
262 |
|
263 |
|
264 TInt CAsyncTransformer::SetScaleQuality(TInt aQualityValue) |
|
265 { |
|
266 iScaleQuality = aQualityValue; |
|
267 return KErrNone; |
|
268 } |
|
269 |
|
270 void CAsyncTransformer::Restart() |
|
271 { |
|
272 iTransformTodo = iSingleton->TransformOptions(); |
|
273 iCurrentSource = iImgSource; |
|
274 iState = EStart; |
|
275 |
|
276 iResultStatus = KErrNone; |
|
277 RunAgain(); |
|
278 } |
|
279 |
|
280 void CAsyncTransformer::RunAgain() |
|
281 { |
|
282 SetActive(); |
|
283 TRequestStatus* pR=&iStatus; |
|
284 User::RequestComplete(pR,KErrNone); |
|
285 } |
|
286 |
|
287 /*static*/ |
|
288 CTransformerSharedData* CTransformerSharedData::NewL() |
|
289 { |
|
290 CTransformerSharedData* self = new (ELeave) CTransformerSharedData(); |
|
291 self->AddRef(); |
|
292 return self; |
|
293 } |
|
294 |
|
295 void CTransformerSharedData::AddRef() |
|
296 { |
|
297 ++iRefCount; |
|
298 } |
|
299 |
|
300 void CTransformerSharedData::Release() |
|
301 { |
|
302 ASSERT(iRefCount>0); |
|
303 if (--iRefCount==0) |
|
304 { |
|
305 delete this; |
|
306 } |
|
307 } |
|
308 |
|
309 |
|
310 void CTransformerSharedData::Cleanup() |
|
311 { |
|
312 delete iScaler; |
|
313 iScaler = NULL; |
|
314 delete iRotator; |
|
315 iRotator= NULL; |
|
316 } |
|
317 |
|
318 CTransformerSharedData::~CTransformerSharedData() |
|
319 { |
|
320 ASSERT(iRefCount==0); |
|
321 Cleanup(); |
|
322 } |
|
323 |
|
324 inline |
|
325 CBitmapScaler& CTransformerSharedData::ScalerL() |
|
326 { |
|
327 if (iScaler==NULL) |
|
328 { |
|
329 iScaler=CBitmapScaler::NewL(); |
|
330 } |
|
331 return *iScaler; |
|
332 } |
|
333 |
|
334 inline |
|
335 CBitmapRotator& CTransformerSharedData::RotatorL() |
|
336 { |
|
337 if (iRotator == NULL) |
|
338 { |
|
339 iRotator = CBitmapRotator::NewL(); |
|
340 } |
|
341 return *iRotator; |
|
342 } |
|
343 |