|
1 // Copyright (c) 1999-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 <fbs.h> |
|
17 #include "ICOCodec.h" |
|
18 #include "icomaskprocessor.h" |
|
19 |
|
20 |
|
21 // Constants. |
|
22 const TInt KIcoInfoHeaderSize = 40; |
|
23 const TInt KRgbQuadSize = 4; |
|
24 const TInt KFullyOpaque = 0x7FFFFFFF; |
|
25 const TInt KFullyTransparent = 0x00000000; |
|
26 const TUint KBlack = 0xFF000000; |
|
27 const TUint KWhite = 0xFFFFFFFF; |
|
28 |
|
29 |
|
30 // CIcoReadCodec |
|
31 CIcoReadCodec::CIcoReadCodec(TInt aIconHeadersToProcess) |
|
32 : iIconHeadersToProcess(aIconHeadersToProcess) |
|
33 {} |
|
34 |
|
35 CIcoReadCodec::~CIcoReadCodec() |
|
36 { |
|
37 } |
|
38 |
|
39 CIcoReadCodec* CIcoReadCodec::NewL(TInt aIconHeadersToProcess) |
|
40 { |
|
41 CIcoReadCodec* self = new(ELeave) CIcoReadCodec(aIconHeadersToProcess); |
|
42 CleanupStack::PushL(self); |
|
43 self->ConstructL(); |
|
44 CleanupStack::Pop(self); |
|
45 return self; |
|
46 } |
|
47 |
|
48 void CIcoReadCodec::InitFrameHeader(TFrameInfo& aFrameSettings, CFrameImageData& /* aFrameImageData */) |
|
49 { |
|
50 ASSERT(aFrameSettings.CurrentFrameState() == TFrameInfo::EFrameInfoUninitialised); |
|
51 iFrameInfo= &aFrameSettings; |
|
52 iFrameInfo->SetCurrentFrameState(TFrameInfo::EFrameInfoProcessingFrameHeader); |
|
53 } |
|
54 |
|
55 TFrameState CIcoReadCodec::ProcessFrameHeaderL(TBufPtr8& aData) |
|
56 { |
|
57 |
|
58 if (iFrameInfo->CurrentFrameState() == TFrameInfo::EFrameInfoProcessingFrame) |
|
59 { |
|
60 if(aData.Length()>=iImageDataBytes) |
|
61 { |
|
62 aData.Shift(iImageDataBytes); |
|
63 iImageDataBytes = 0; |
|
64 |
|
65 iFrameInfo->SetCurrentFrameState(TFrameInfo::EFrameInfoProcessingComplete); |
|
66 if ((--iIconHeadersToProcess) == 0) |
|
67 return EFrameComplete; |
|
68 } |
|
69 else |
|
70 { |
|
71 iImageDataBytes -= aData.Length(); |
|
72 aData.Shift(aData.Length()); |
|
73 } |
|
74 } |
|
75 |
|
76 if (iFrameInfo->CurrentFrameState() == TFrameInfo::EFrameInfoProcessingFrameHeader) |
|
77 { // If processing of previous frame info complete or if its the first frame. |
|
78 if (aData.Length() < KIcoInfoHeaderSize) |
|
79 User::Leave(KErrUnderflow); |
|
80 |
|
81 const TUint8* data = STATIC_CAST(const TUint8*, aData.Ptr()); |
|
82 |
|
83 const TInt width = data[4] + (data[5] << 8) + (data[6] << 16) + (data[7] << 24); |
|
84 const TInt height = (data[8] + (data[9] << 8) + (data[10] << 16) + (data[11] << 24))/2; |
|
85 |
|
86 if(width <= 0 || height <= 0) |
|
87 User::Leave(KErrCorrupt); |
|
88 |
|
89 iFrameInfo->iBitsPerPixel = data[14] + (data[15] << 8); |
|
90 const TInt colors = 1 << iFrameInfo->iBitsPerPixel; |
|
91 |
|
92 // Calculate image size. (Pixels) |
|
93 iFrameInfo->iOverallSizeInPixels.SetSize(width, height); |
|
94 |
|
95 // Calculate image size. (Bytes) |
|
96 // XOR image. |
|
97 iImageDataBytes = (width*iFrameInfo->iBitsPerPixel + 31)/32; |
|
98 |
|
99 if(iImageDataBytes <= 0) //overflow |
|
100 User::Leave(KErrCorrupt); |
|
101 |
|
102 // AND image. |
|
103 iImageDataBytes += (width + 31)/32; |
|
104 |
|
105 if(iImageDataBytes <= 0) //overflow |
|
106 User::Leave(KErrCorrupt); |
|
107 |
|
108 iImageDataBytes *= 4*height; |
|
109 |
|
110 if(iImageDataBytes <= 0) //overflow |
|
111 User::Leave(KErrCorrupt); |
|
112 |
|
113 // Include the palette as well. |
|
114 iImageDataBytes += colors*KRgbQuadSize; |
|
115 |
|
116 if(iImageDataBytes <= 0) //overflow |
|
117 User::Leave(KErrCorrupt); |
|
118 |
|
119 iFrameInfo->iFrameCoordsInPixels.SetRect(TPoint(0,0), iFrameInfo->iOverallSizeInPixels); |
|
120 iFrameInfo->iFrameSizeInTwips.SetSize(0, 0); |
|
121 iFrameInfo->iDelay = 0; |
|
122 iFrameInfo->iFlags |= TFrameInfo::ETransparencyPossible | TFrameInfo::EPartialDecodeInvalid; |
|
123 |
|
124 if (iFrameInfo->iFrameCoordsInPixels.iBr.iX < 0 || iFrameInfo->iFrameCoordsInPixels.iBr.iY < 0 || |
|
125 !(iFrameInfo->iBitsPerPixel == 1 || iFrameInfo->iBitsPerPixel == 4 || |
|
126 iFrameInfo->iBitsPerPixel == 8)) |
|
127 User::Leave(KErrCorrupt); |
|
128 |
|
129 if (iFrameInfo->iBitsPerPixel > 1) |
|
130 iFrameInfo->iFlags |= TFrameInfo::EColor; |
|
131 |
|
132 switch (iFrameInfo->iBitsPerPixel) |
|
133 { |
|
134 case 1: |
|
135 iFrameInfo->iFrameDisplayMode = EGray2; |
|
136 break; |
|
137 |
|
138 case 4: |
|
139 iFrameInfo->iFrameDisplayMode = EColor16; |
|
140 iFrameInfo->iFlags |= TFrameInfo::EColor; |
|
141 break; |
|
142 |
|
143 case 8: |
|
144 iFrameInfo->iFrameDisplayMode = EColor256; |
|
145 iFrameInfo->iFlags |= TFrameInfo::EColor; |
|
146 break; |
|
147 } |
|
148 |
|
149 aData.Shift(KIcoInfoHeaderSize); |
|
150 TInt frameDataOffset = iFrameInfo->FrameDataOffset(); |
|
151 iFrameInfo->SetFrameDataOffset(frameDataOffset + KIcoInfoHeaderSize); |
|
152 |
|
153 iFrameInfo->SetCurrentFrameState(TFrameInfo::EFrameInfoProcessingFrame); |
|
154 } |
|
155 |
|
156 return EFrameIncomplete; |
|
157 } |
|
158 |
|
159 TFrameState CIcoReadCodec::ProcessFrameL(TBufPtr8& aSrc) |
|
160 { |
|
161 if (iNewFrame) |
|
162 { |
|
163 // Extract the palette. |
|
164 TInt colors = 1 << iFrameInfo->iBitsPerPixel; |
|
165 |
|
166 if (aSrc.Length()<(colors*KRgbQuadSize)) |
|
167 return EFrameIncomplete; |
|
168 |
|
169 const TUint8* aSrcPtr = aSrc.Ptr(); |
|
170 TInt baseIndex; |
|
171 for (TInt paletteIndex = 0; paletteIndex < colors; paletteIndex++) |
|
172 { |
|
173 baseIndex = KRgbQuadSize*paletteIndex; |
|
174 iPalette[paletteIndex] = TRgb(aSrcPtr[baseIndex+2],aSrcPtr[baseIndex+1],aSrcPtr[baseIndex]); |
|
175 } |
|
176 |
|
177 aSrc.Shift(colors*KRgbQuadSize); |
|
178 |
|
179 iNewFrame = EFalse; |
|
180 } |
|
181 |
|
182 if (aSrc.Length() == 0) |
|
183 return EFrameIncomplete; |
|
184 |
|
185 TUint8* srcStart = CONST_CAST(TUint8*,aSrc.Ptr()); |
|
186 iDataPtr = srcStart; |
|
187 iDataPtrLimit = srcStart + aSrc.Length(); |
|
188 |
|
189 DoProcessL(); |
|
190 |
|
191 TInt bytesUsed = iDataPtr - srcStart; |
|
192 aSrc.Shift(bytesUsed); |
|
193 |
|
194 ASSERT(iBmpBytesExpected>=0); // not clear if value can be negative - if it does occur, need to think about it |
|
195 |
|
196 if (iBmpBytesExpected > 0) |
|
197 { |
|
198 const TInt bmpBytesUsed = Min(bytesUsed, iBmpBytesExpected); |
|
199 iBmpBytesExpected -= bmpBytesUsed; |
|
200 bytesUsed -= bmpBytesUsed; |
|
201 } |
|
202 |
|
203 CImageProcessor*const imageProc = ImageProcessor(); |
|
204 CImageProcessor*const maskProc = MaskProcessor(); |
|
205 |
|
206 if (bytesUsed > 0 && maskProc) |
|
207 { |
|
208 const TInt maskBytesUsed = Min(bytesUsed, iMaskBytesExpected); |
|
209 iMaskBytesExpected -= maskBytesUsed; |
|
210 } |
|
211 |
|
212 if ((!maskProc && iBmpBytesExpected <= 0) || (maskProc && iMaskBytesExpected <= 0)) |
|
213 { |
|
214 imageProc->FlushPixels(); |
|
215 if (maskProc) |
|
216 maskProc->FlushPixels(); |
|
217 |
|
218 iNewFrame = ETrue; |
|
219 Pos().SetXY(0,0); |
|
220 return EFrameComplete; |
|
221 } |
|
222 |
|
223 return EFrameIncomplete; |
|
224 } |
|
225 |
|
226 void CIcoReadCodec::InitFrameL(TFrameInfo& aFrameInfo, CFrameImageData& /*aFrameImageData*/, TBool aDisableErrorDiffusion, CFbsBitmap& aDestination, CFbsBitmap* aDestinationMask) |
|
227 { |
|
228 |
|
229 iFrameInfo= &aFrameInfo; |
|
230 CFbsBitmap& newFrame = aDestination; |
|
231 |
|
232 TSize& originalSize = iFrameInfo->iOverallSizeInPixels; |
|
233 Pos().iY = originalSize.iHeight - 1; |
|
234 |
|
235 const TDisplayMode dispMode = (iFrameInfo->iBitsPerPixel == 1) ? EGray2 : EColor256; |
|
236 const TSize destinationSize(aDestination.SizeInPixels()); |
|
237 |
|
238 TInt reductionFactor = ReductionFactor(originalSize, destinationSize); |
|
239 CImageProcessor* imageProc = ImageProcessorUtility::NewImageProcessorL(aDestination, reductionFactor, dispMode, aDisableErrorDiffusion); |
|
240 SetImageProcessor(imageProc); |
|
241 |
|
242 imageProc->PrepareL(newFrame, originalSize); |
|
243 imageProc->SetPos(TPoint(0, originalSize.iHeight - 1)); |
|
244 imageProc->SetYPosIncrement(-1); |
|
245 |
|
246 CImageProcessor* maskProc = NULL; |
|
247 SetMaskProcessor(NULL); |
|
248 |
|
249 if (aDestinationMask) |
|
250 { |
|
251 CFbsBitmap& newMaskFrame = *aDestinationMask; |
|
252 maskProc = ImageProcessorUtility::NewImageProcessorL(newMaskFrame, originalSize, EGray2, aDisableErrorDiffusion); |
|
253 SetMaskProcessor(maskProc); |
|
254 maskProc->PrepareL(newMaskFrame, originalSize); |
|
255 } |
|
256 else if (newFrame.DisplayMode() == EColor16MA) |
|
257 { |
|
258 // 16MA dest and no mask - special case |
|
259 maskProc = CIcoMaskProcessor::NewL(reductionFactor); |
|
260 SetMaskProcessor(maskProc); |
|
261 maskProc->PrepareL(newFrame, originalSize); // uses destination bitmap |
|
262 } |
|
263 |
|
264 if(maskProc) |
|
265 { |
|
266 maskProc->SetPos(TPoint(0,originalSize.iHeight - 1)); |
|
267 maskProc->SetYPosIncrement(-1); |
|
268 const TInt maskWidth = (originalSize.iWidth + 31) & ~31; // round up to 32-byte boundary |
|
269 maskProc->SetPixelPadding(maskWidth - originalSize.iWidth); |
|
270 iMaskBytesExpected = (maskWidth * originalSize.iHeight) / 8; |
|
271 } |
|
272 |
|
273 const TInt actualWidth = (((originalSize.iWidth * iFrameInfo->iBitsPerPixel) + 31) & ~31) / iFrameInfo->iBitsPerPixel; // round up to 32-byte boundary |
|
274 imageProc->SetPixelPadding(actualWidth - originalSize.iWidth); |
|
275 |
|
276 iBmpBytesExpected = (actualWidth * originalSize.iHeight * iFrameInfo->iBitsPerPixel) / 8; // bits are packed into bytes |
|
277 |
|
278 iNewFrame =ETrue; |
|
279 } |
|
280 |
|
281 void CIcoReadCodec::DoProcessL() |
|
282 { |
|
283 const TUint8* bmpDataPtrLimit = Min(iDataPtrLimit, iDataPtr + iBmpBytesExpected); |
|
284 CImageProcessor*const imageProc = ImageProcessor(); |
|
285 switch (iFrameInfo->iBitsPerPixel) |
|
286 { |
|
287 case 1: |
|
288 while (iDataPtr < bmpDataPtrLimit) |
|
289 { |
|
290 TUint8 value = *iDataPtr++; |
|
291 |
|
292 // code will compare value with successive masks 0x80, 0x80 etc downto but not including |
|
293 for (TUint mask=0x80; mask!=0; mask >>= 1) |
|
294 imageProc->SetPixel((value & mask) ? iPalette[1] : iPalette[0]); |
|
295 } |
|
296 break; |
|
297 case 4: |
|
298 while (iDataPtr < bmpDataPtrLimit) |
|
299 { |
|
300 TUint8 value = *iDataPtr++; |
|
301 |
|
302 imageProc->SetPixel(iPalette[value >> 4]); |
|
303 imageProc->SetPixel(iPalette[value & 0x0f]); |
|
304 } |
|
305 break; |
|
306 case 8: |
|
307 while (iDataPtr < bmpDataPtrLimit) |
|
308 imageProc->SetPixel(iPalette[*iDataPtr++]); |
|
309 break; |
|
310 default: |
|
311 User::Leave(KErrCorrupt); |
|
312 break; |
|
313 } |
|
314 |
|
315 CImageProcessor*const maskProc = MaskProcessor(); |
|
316 if (maskProc) |
|
317 { |
|
318 // force a flush |
|
319 imageProc->FlushPixels(); |
|
320 |
|
321 const TUint8* maskDataPtrLimit = Min(iDataPtrLimit, iDataPtr + iMaskBytesExpected); |
|
322 |
|
323 while (iDataPtr < maskDataPtrLimit) |
|
324 { |
|
325 TUint8 value = *iDataPtr++; |
|
326 |
|
327 // code will compare value with successive masks 0x80, 0x80 etc downto but not including |
|
328 for (TUint mask=0x80; mask!=0; mask >>= 1) |
|
329 { |
|
330 maskProc->SetPixel((value & mask) ? TRgb(KBlack, KFullyTransparent) : TRgb(KWhite, KFullyOpaque)); |
|
331 } |
|
332 } |
|
333 } |
|
334 } |