|
1 // Copyright (c) 2006-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 "BMDRAW.H" |
|
17 #include <graphics/lookuptable.h> |
|
18 #include <graphics/blendingalgorithms.h> |
|
19 |
|
20 /* |
|
21 Does the same conversion as NonPMA2PMAPixel, but leaves the values in the RB and G uint32 values |
|
22 ready for use in the blending algorithm. Also assumes alphas of 0 or 0xFF have already been |
|
23 stripped out as special cases. |
|
24 */ |
|
25 FORCEINLINE void NonPMA2PMAPixelRBG(TUint32 aPixel, TUint32 &aSrcRB, TUint32 &aSrcG, TUint32 &aMask) |
|
26 { |
|
27 TUint32 alpha=(aPixel >> 24); |
|
28 aMask = 0x0100 - alpha; // for use in PMABlend_fromRBandG |
|
29 TUint32 tap1=alpha+1; |
|
30 aSrcRB = (aPixel & KRBMask) * tap1; |
|
31 aSrcRB >>= 8; |
|
32 aSrcRB &= KRBMask; |
|
33 aSrcG = (aPixel&0xFF000000) | (((aPixel & KGMask)>>8) * tap1) & KAGMask; |
|
34 } |
|
35 |
|
36 /* |
|
37 Uses same algorithm as PMABlend_noChecksInplace, but optimised for use with NonPMA2PMAPixelRBG where |
|
38 source values are pre-split into RB and G components ready for use in blend |
|
39 */ |
|
40 FORCEINLINE void PMABlend_fromRBandG(TUint32& aDest_io, const TUint32 aSrcRB, const TUint32 aSrcG, const TUint8 aMask) |
|
41 { |
|
42 TUint32 dst_ag = (aDest_io & KAGMask) >> 8; |
|
43 aDest_io = aDest_io & KRBMask; |
|
44 aDest_io = (aSrcRB + ((aMask * aDest_io) >> 8)) & KRBMask; |
|
45 aDest_io |= (aSrcG + (aMask * dst_ag)) & KAGMask; |
|
46 } |
|
47 |
|
48 /* |
|
49 Takes a non-PM source colour and an alpha value |
|
50 First pre-multiplies aSrcPixel with aAlpha |
|
51 Then blends it into aDestIo using the same alpha value. |
|
52 */ |
|
53 FORCEINLINE void PMABlend_FromNonPmAndAlpha(TUint32& aDest_io, const TUint32& aSrcPixel, TUint32 aAlpha) |
|
54 { |
|
55 TUint32 tap1=aAlpha+1; |
|
56 TUint32 srcRB = (aSrcPixel & KRBMask) * tap1; |
|
57 srcRB=(srcRB>>8) & KRBMask; |
|
58 TUint32 srcAG = (aSrcPixel & KGMask ) * tap1; |
|
59 srcAG=(srcAG>>8) & KGMask; |
|
60 srcAG|=aAlpha<<24; |
|
61 |
|
62 TUint32 dst_ag = (aDest_io & KAGMask) >> 8; |
|
63 TUint32 dst_rb = aDest_io & KRBMask; |
|
64 const TUint32 mask = 0x0100 - aAlpha; |
|
65 aDest_io = (srcRB + ((mask*dst_rb) >> 8)) & KRBMask; |
|
66 aDest_io |= (srcAG + mask*dst_ag) & KAGMask; |
|
67 } |
|
68 |
|
69 // Same as NonPMA2PMAPixel, but for use where checks for alpha of 0 or 0xFF have already been done |
|
70 FORCEINLINE TUint32 NonPMA2PMAPixelNoCheck(TUint32 aPixel) |
|
71 { |
|
72 TUint32 tap1=(aPixel>>24)+1; |
|
73 TUint32 scaledRB = (aPixel & KRBMask) * tap1; |
|
74 TUint32 scaledG = (aPixel & KGMask ) * tap1; |
|
75 return (aPixel & 0xff000000) | ((scaledRB>>8) & KRBMask) | ((scaledG>>8)& KGMask); |
|
76 } |
|
77 |
|
78 /** |
|
79 Composite mask application |
|
80 where AlphaComposite = AlphaColor * AlphaMask / 255. |
|
81 @param aColor - non-premltiplied color with alpha |
|
82 @param aMask - the mask value. (0 to 255). |
|
83 @return the color with alpha combined from color and mask (combination |
|
84 operator used is scaled multiplication). |
|
85 */ |
|
86 FORCEINLINE TUint32 CompMask(TUint32 aColor, TUint8 aMask) |
|
87 { |
|
88 // if the mask is FF the colour will be fully opaque and can be immediatly returned |
|
89 if (aMask == 0xff) |
|
90 return aColor; |
|
91 |
|
92 TUint32 cAlpha = (aMask+1) * (aColor >> 24); |
|
93 return ((aColor & 0x00ffffff) | ((cAlpha <<16) & 0xff000000)); |
|
94 } |
|
95 |
|
96 TInt CDrawThirtyTwoBppBitmapAlphaPM::Construct(TSize aSize) |
|
97 { |
|
98 return Construct(aSize, aSize.iWidth << 2); |
|
99 } |
|
100 |
|
101 TInt CDrawThirtyTwoBppBitmapAlphaPM::Construct(TSize aSize, TInt aStride) |
|
102 { |
|
103 iDispMode = EColor16MAP; |
|
104 return CDrawThirtyTwoBppBitmapCommon::Construct(aSize, aStride); |
|
105 } |
|
106 |
|
107 /** |
|
108 MAlphaBlend::WriteRgbAlphaLine() implementation. |
|
109 Blends the supplied buffer of TRgb format data (ARGB), and the mask, to the destination |
|
110 which is specified by the pixel positions aX, aY and length. |
|
111 @param aX The starting position on the x-axis for the destination pixel. |
|
112 @param aY The starting position on the y-axis for the destination pixel. |
|
113 @param aRgbBuffer The RGB source data buffer. This is assumed to be bit aligned 32 bit non-premultiplied data |
|
114 @param aMaskBuffer The masking data. The mask buffer and the source alpha values are multiplied together to |
|
115 generate the alpha used for blending to the destination. |
|
116 @param aShadowing The shadowing flag. Indicates when and how to apply shadowing. |
|
117 @param aDrawMode The mode for rendering the source image to the destination. |
|
118 Currently supports EWriteAlpha and EPenmode. |
|
119 |
|
120 @see MAlphaBlend::WriteRgbAlphaLine() |
|
121 */ |
|
122 void CDrawThirtyTwoBppBitmapAlphaPM::WriteRgbAlphaLine(TInt aX, TInt aY, TInt aLength, |
|
123 const TUint8* aRgbBuffer, |
|
124 const TUint8* aMaskBuffer, |
|
125 MAlphaBlend::TShadowing aShadowing, |
|
126 CGraphicsContext::TDrawMode aDrawMode) |
|
127 { |
|
128 // precondition for this function is that the aRgbBuffer lies on a word boundary |
|
129 // Assert checks that the pointer is at a word boundary |
|
130 __ASSERT_DEBUG(!(((TUint)aRgbBuffer) & 0x3), Panic(EScreenDriverPanicInvalidPointer)); |
|
131 |
|
132 DeOrientate(aX,aY); |
|
133 TUint32* pixelPtr = PixelAddress(aX,aY); |
|
134 const TInt pixelPtrInc = PixelAddressIncrement(); |
|
135 const TUint16* normTable = PtrTo16BitNormalisationTable(); |
|
136 TRgb tmp; |
|
137 const TUint8* maskBufferPtrLimit = aMaskBuffer + aLength; |
|
138 // The purpose of this conditional is to remove if statements from within the loop |
|
139 // if shadow mode is not enabled and the UserDispMode is none or EColor16MAP |
|
140 if(!(iShadowMode & (EFade | EShadow)) && (iUserDispMode ==EColor16MAP || iUserDispMode == ENone)) |
|
141 { |
|
142 while (aMaskBuffer < maskBufferPtrLimit) |
|
143 { |
|
144 if (*aMaskBuffer) |
|
145 { |
|
146 TUint32 srcData = *((TUint32*)aRgbBuffer); |
|
147 if ((aDrawMode == CGraphicsContext::EDrawModeWriteAlpha) && (*aMaskBuffer == 0xFF)) |
|
148 { |
|
149 // Write the source straight through to the target, otherwise |
|
150 // blend. This relies on the fact that EDrawModeWriteAlpha can only |
|
151 // be used with masks that contain only black or white. |
|
152 Convert2PMA(srcData); |
|
153 *pixelPtr = srcData; |
|
154 } |
|
155 else |
|
156 { |
|
157 //blend alpha value in source with the mask value. |
|
158 srcData = CompMask(srcData, *aMaskBuffer); |
|
159 //pre-multiply, inplace. |
|
160 Convert2PMA(srcData); |
|
161 PMAInplaceBlend(*pixelPtr, srcData); |
|
162 } |
|
163 } |
|
164 pixelPtr += pixelPtrInc; |
|
165 aRgbBuffer += 4; |
|
166 aMaskBuffer++; |
|
167 } |
|
168 } |
|
169 else |
|
170 { |
|
171 while (aMaskBuffer < maskBufferPtrLimit) |
|
172 { |
|
173 TUint32 srcColor = *((TUint32*)(aRgbBuffer)); |
|
174 if(*aMaskBuffer) |
|
175 { |
|
176 if(aShadowing == MAlphaBlend::EShdwBefore) |
|
177 { |
|
178 // src color in non-premultiplied. |
|
179 Shadow(*(TRgb*)&srcColor); |
|
180 } |
|
181 TUint32 srcData; |
|
182 if ((aDrawMode == CGraphicsContext::EDrawModeWriteAlpha) && (*aMaskBuffer == 0xFF)) |
|
183 { |
|
184 Convert2PMA(srcColor); |
|
185 srcData = srcColor; |
|
186 } |
|
187 else |
|
188 { |
|
189 //blend alpha value in source with the mask value. |
|
190 srcData = CompMask(srcColor, *aMaskBuffer); |
|
191 //pre-multiply, inplace. |
|
192 Convert2PMA(srcData); |
|
193 srcData = PMAPixelBlend(*pixelPtr, srcData); |
|
194 } |
|
195 |
|
196 if(aShadowing == MAlphaBlend::EShdwAfter) |
|
197 { |
|
198 // shadow is done in PMA mode. |
|
199 Shadow(srcData); |
|
200 } |
|
201 if(iUserDispMode !=EColor16MAP && iUserDispMode != ENone) |
|
202 { |
|
203 tmp.SetInternal(PMA2NonPMAPixel(srcData, normTable)); |
|
204 CDrawThirtyTwoBppBitmapCommon::MapColorToUserDisplayMode(tmp); |
|
205 srcData = tmp.Internal(); |
|
206 Convert2PMA(srcData); |
|
207 } |
|
208 *pixelPtr = srcData; |
|
209 } |
|
210 pixelPtr += pixelPtrInc; |
|
211 aRgbBuffer += 4; |
|
212 aMaskBuffer++; |
|
213 } |
|
214 } |
|
215 } |
|
216 |
|
217 /** |
|
218 This assumes that the pen color (aColor) alpha information is to be blended with |
|
219 the alpha provided by the mask buffer. |
|
220 If pen is opaque, the mask is used as transparency information to be used. |
|
221 If pen is semi-transparent, the mask is contructed by calculating the resulting alpha |
|
222 by multiplying the mask with the alpha information of the pen color. |
|
223 @see CFbsDrawDevice::WriteRgbAlphaMulti |
|
224 */ |
|
225 void CDrawThirtyTwoBppBitmapAlphaPM::WriteRgbAlphaMulti(TInt aX,TInt aY,TInt aLength,TRgb aColor,const TUint8* aMaskBuffer) |
|
226 { |
|
227 TUint32 srcAlpha = aColor.Alpha(); |
|
228 if (srcAlpha==0 || aLength<=0) |
|
229 return; |
|
230 DeOrientate(aX,aY); |
|
231 TUint32* pixelPtr = PixelAddress(aX,aY); |
|
232 const TInt pixelPtrInc = PixelAddressIncrement(); |
|
233 const TUint8* maskBufferPtrLimit = aMaskBuffer + aLength; |
|
234 if (iShadowMode) |
|
235 CDrawThirtyTwoBppBitmapCommon::Shadow(aColor); |
|
236 // pre-multiply the color. |
|
237 const TUint32 srcColor = aColor.Internal(); |
|
238 if (srcAlpha == 255) |
|
239 { // source (pen) is opaque, so we simply blend it using the mask |
|
240 // little trick to make main loop more optimised, having 'pixelPtr += pixelPtrInc' at the top |
|
241 // of the loop makes the compiler generate better code without extra jumps to reach the |
|
242 // 'pixelPtr += pixelPtrInc' line. |
|
243 // We also need to do the FOREVER loop with a break when aMaskBuffer==maskBufferPtrLimit or |
|
244 // else the compiler puts the test at the end and extra jumps are required to reach it. |
|
245 pixelPtr -= pixelPtrInc; |
|
246 FOREVER |
|
247 { |
|
248 pixelPtr += pixelPtrInc; |
|
249 if (aMaskBuffer==maskBufferPtrLimit) |
|
250 break; |
|
251 const TUint maskAlpha=*aMaskBuffer++; |
|
252 if (maskAlpha==0) |
|
253 { // Most pixels in text are blank, so this is the most important route to optimise |
|
254 continue; |
|
255 } |
|
256 else if (maskAlpha==0xFF) |
|
257 { // Second most important are fully opaque pixels |
|
258 *pixelPtr=srcColor; |
|
259 continue; |
|
260 } |
|
261 TUint32 maskColor = NonPMA2PMAPixelNoCheck((srcColor&~0xFF000000) | ((TUint32)maskAlpha << 24)); |
|
262 PMAInplaceBlend(*pixelPtr, maskColor); |
|
263 } |
|
264 } |
|
265 else if(srcAlpha > 0) |
|
266 { |
|
267 // pen is semi-transparent, so we must blend using both the mask and pen alpha |
|
268 // pre calculate ffMaskColor optimised for common case where aMaskBuffer contains 0xFF |
|
269 const TUint32 ffMaskColor=NonPMA2PMAPixelNoCheck(srcColor); |
|
270 const TUint32 noAlphaSrcColor=srcColor&0xFFFFFF; |
|
271 while (aMaskBuffer < maskBufferPtrLimit) |
|
272 { |
|
273 const TUint maskAlpha=*aMaskBuffer; |
|
274 if (maskAlpha) |
|
275 { |
|
276 if (maskAlpha==0xFF) |
|
277 PMABlend_noChecksInplace(*pixelPtr, ffMaskColor, srcAlpha); |
|
278 else |
|
279 { |
|
280 TUint32 mixedAlpha = ((maskAlpha+1) * srcAlpha)>>8; |
|
281 PMABlend_FromNonPmAndAlpha(*pixelPtr, noAlphaSrcColor, mixedAlpha); |
|
282 } |
|
283 } |
|
284 pixelPtr += pixelPtrInc; |
|
285 aMaskBuffer++; |
|
286 } |
|
287 } |
|
288 } |
|
289 |
|
290 /** |
|
291 @see CFbsDrawDevice::WriteRgb |
|
292 */ |
|
293 void CDrawThirtyTwoBppBitmapAlphaPM::WriteRgb(TInt aX,TInt aY,TRgb aColor) |
|
294 { |
|
295 TUint32 srcColor = NonPMA2PMAPixel(aColor.Internal()); |
|
296 TUint32* pixelPtr = PixelAddress(aX,aY); |
|
297 PMAInplaceBlend(*pixelPtr, srcColor); |
|
298 } |
|
299 |
|
300 /** |
|
301 @see CFbsDrawDevice::WriteBinary |
|
302 */ |
|
303 void CDrawThirtyTwoBppBitmapAlphaPM::WriteBinary(TInt aX,TInt aY,TUint32* aBuffer,TInt aLength,TInt aHeight,TRgb aColor) |
|
304 { |
|
305 const TUint32 colorInternal=aColor.Internal(); |
|
306 const TUint8 srcAlpha = colorInternal >> 24; |
|
307 if (srcAlpha==0) |
|
308 return; |
|
309 DeOrientate(aX,aY); |
|
310 |
|
311 TInt pixelInc; |
|
312 TInt rowInc; |
|
313 |
|
314 switch(iOrientation) |
|
315 { |
|
316 case EOrientationNormal: |
|
317 { |
|
318 pixelInc = 1; |
|
319 rowInc = iScanLineWords; |
|
320 break; |
|
321 } |
|
322 case EOrientationRotated90: |
|
323 { |
|
324 pixelInc = iScanLineWords; |
|
325 rowInc = -1; |
|
326 break; |
|
327 } |
|
328 case EOrientationRotated180: |
|
329 { |
|
330 pixelInc = -1; |
|
331 rowInc = -iScanLineWords; |
|
332 break; |
|
333 } |
|
334 default: // EOrientationRotated270 |
|
335 { |
|
336 pixelInc = -iScanLineWords; |
|
337 rowInc = 1; |
|
338 } |
|
339 } |
|
340 |
|
341 const TUint32* dataLimit = aBuffer + aHeight; |
|
342 const TUint32 dataMaskLimit = (aLength < 32) ? 1 << aLength : 0; |
|
343 |
|
344 TUint32* pixelPtr = PixelAddress(aX,aY); |
|
345 if (srcAlpha==0xFF) |
|
346 { |
|
347 while (aBuffer < dataLimit) |
|
348 { |
|
349 TUint32 dataWord = *aBuffer++; |
|
350 TUint32 dataMask = 1; |
|
351 TUint32* tempPixelPtr = pixelPtr; |
|
352 while (dataMask != dataMaskLimit) |
|
353 { |
|
354 if(dataWord & dataMask) |
|
355 { |
|
356 *tempPixelPtr=colorInternal; |
|
357 } |
|
358 |
|
359 tempPixelPtr += pixelInc; |
|
360 dataMask <<= 1; |
|
361 } |
|
362 |
|
363 pixelPtr += rowInc; |
|
364 } |
|
365 } |
|
366 else |
|
367 { |
|
368 TUint32 src_rb; |
|
369 TUint32 src_g; |
|
370 TUint32 mask; |
|
371 //pre-multiply the src color, before blending. |
|
372 NonPMA2PMAPixelRBG(colorInternal,src_rb,src_g,mask); |
|
373 while (aBuffer < dataLimit) |
|
374 { |
|
375 TUint32 dataWord = *aBuffer++; |
|
376 TUint32 dataMask = 1; |
|
377 TUint32* tempPixelPtr = pixelPtr; |
|
378 while (dataMask != dataMaskLimit) |
|
379 { |
|
380 if(dataWord & dataMask) |
|
381 { |
|
382 PMABlend_fromRBandG(*tempPixelPtr, src_rb, src_g, mask); |
|
383 } |
|
384 |
|
385 tempPixelPtr += pixelInc; |
|
386 dataMask <<= 1; |
|
387 } |
|
388 |
|
389 pixelPtr += rowInc; |
|
390 } |
|
391 } |
|
392 } |
|
393 |
|
394 /** |
|
395 @see CFbsDrawDevice::WriteBinaryLineVertical |
|
396 */ |
|
397 void CDrawThirtyTwoBppBitmapAlphaPM::WriteBinaryLineVertical(TInt aX,TInt aY,TUint32* aBuffer,TInt aHeight,TRgb aColor,TBool aUp) |
|
398 { |
|
399 const TUint32 colorInternal=aColor.Internal(); |
|
400 const TInt sourceAlpha = colorInternal>>24; |
|
401 if (sourceAlpha==0) |
|
402 return; |
|
403 |
|
404 DeOrientate(aX,aY); |
|
405 |
|
406 TInt scanlineWordLength; |
|
407 |
|
408 switch(iOrientation) |
|
409 { |
|
410 case EOrientationNormal: |
|
411 scanlineWordLength = iScanLineWords; |
|
412 break; |
|
413 case EOrientationRotated90: |
|
414 scanlineWordLength = -1; |
|
415 break; |
|
416 case EOrientationRotated180: |
|
417 scanlineWordLength = -iScanLineWords; |
|
418 break; |
|
419 default: // EOrientationRotated270 |
|
420 scanlineWordLength = 1; |
|
421 } |
|
422 |
|
423 if (aUp) |
|
424 scanlineWordLength = -scanlineWordLength; |
|
425 |
|
426 TUint32* pixelPtr = PixelAddress(aX,aY); |
|
427 const TUint32* pixelPtrLimit = pixelPtr + (aHeight * scanlineWordLength); |
|
428 TUint32 dataWord = *aBuffer; |
|
429 TUint32 dataMask = 1; |
|
430 |
|
431 if (sourceAlpha==0xFF) |
|
432 { |
|
433 while(pixelPtr != pixelPtrLimit) |
|
434 { |
|
435 if(!dataMask) |
|
436 { |
|
437 dataMask = 1; |
|
438 aBuffer++; |
|
439 dataWord = *aBuffer; |
|
440 } |
|
441 |
|
442 if(dataWord & dataMask) |
|
443 { |
|
444 *pixelPtr = colorInternal; |
|
445 } |
|
446 dataMask <<= 1; |
|
447 pixelPtr += scanlineWordLength; |
|
448 } |
|
449 } |
|
450 else |
|
451 { |
|
452 TUint32 src_rb; |
|
453 TUint32 src_g; |
|
454 TUint32 mask; |
|
455 //pre-multiply the src color, before blending. |
|
456 NonPMA2PMAPixelRBG(colorInternal,src_rb,src_g,mask); |
|
457 while(pixelPtr != pixelPtrLimit) |
|
458 { |
|
459 if(!dataMask) |
|
460 { |
|
461 dataMask = 1; |
|
462 aBuffer++; |
|
463 dataWord = *aBuffer; |
|
464 } |
|
465 |
|
466 if(dataWord & dataMask) |
|
467 { |
|
468 PMABlend_fromRBandG(*pixelPtr, src_rb, src_g, mask); |
|
469 } |
|
470 dataMask <<= 1; |
|
471 pixelPtr += scanlineWordLength; |
|
472 } |
|
473 } |
|
474 } |
|
475 |
|
476 /** |
|
477 @see CFbsDrawDevice::BlendRgbMulti |
|
478 */ |
|
479 void CDrawThirtyTwoBppBitmapAlphaPM::BlendRgbMulti(TInt aX,TInt aY,TInt aLength,TInt aHeight,TRgb aColor) |
|
480 { |
|
481 const TInt sourceAlpha = aColor.Alpha(); |
|
482 if (sourceAlpha==255)// opaque |
|
483 { |
|
484 WriteRgbMulti(aX,aY,aLength,aHeight,aColor); |
|
485 return; |
|
486 } |
|
487 if (sourceAlpha==0)// transparent |
|
488 return; |
|
489 TUint32* pixelPtr = PixelAddress(aX,aY); |
|
490 TUint32* pixelRowPtrLimit = pixelPtr + (aHeight * iScanLineWords); |
|
491 TUint32* pixelPtrLimit = pixelPtr + aLength; |
|
492 |
|
493 TUint32 srcValue = NonPMA2PMAPixel(aColor.Internal()); |
|
494 TUint32 src_c = srcValue & KRBMask; |
|
495 TUint32 src_g = (srcValue & KAGMask)>>8; |
|
496 const TUint32 mask = 0x0100 - sourceAlpha; |
|
497 while (pixelPtr < pixelRowPtrLimit) |
|
498 { |
|
499 for (TUint32* tempPixelPtr = pixelPtr; tempPixelPtr < pixelPtrLimit; tempPixelPtr++) |
|
500 { |
|
501 const TUint32 dst = *tempPixelPtr; |
|
502 TUint32 dst_c = dst & KRBMask; |
|
503 dst_c = (src_c + ((mask * dst_c)>>8)) & KRBMask; |
|
504 const TUint32 dst_ag = (dst & KAGMask)>>8; |
|
505 dst_c |= ((src_g + ((mask * dst_ag)>>8)) & KRBMask)<<8; |
|
506 *tempPixelPtr=dst_c; |
|
507 } |
|
508 pixelPtr += iScanLineWords; |
|
509 pixelPtrLimit += iScanLineWords; |
|
510 } |
|
511 } |
|
512 |
|
513 /** |
|
514 @see CFbsDrawDevice::BlendLine |
|
515 */ |
|
516 void CDrawThirtyTwoBppBitmapAlphaPM::BlendLine(TInt aX,TInt aY,TInt aLength,TUint32* aBuffer) |
|
517 { |
|
518 TUint32* pixelPtr = PixelAddress(aX,aY); |
|
519 |
|
520 const TUint32* bufferPtrLimit = aBuffer + aLength; |
|
521 const TInt pixelPtrInc = (iOrientation == EOrientationNormal) ? 1 : PixelAddressIncrement(); |
|
522 |
|
523 while (aBuffer < bufferPtrLimit) |
|
524 { |
|
525 PMAInplaceBlend(*pixelPtr, *aBuffer); |
|
526 aBuffer++; |
|
527 pixelPtr += pixelPtrInc; |
|
528 } |
|
529 } |
|
530 /** |
|
531 @see CFbsDrawDevice::ShadowArea |
|
532 */ |
|
533 void CDrawThirtyTwoBppBitmapAlphaPM::ShadowArea(const TRect& aRect) |
|
534 { |
|
535 const TRect rect(DeOrientate(aRect)); |
|
536 __ASSERT_DEBUG(rect.iTl.iX>=0 && rect.iBr.iX<=iSize.iWidth,Panic(EScreenDriverPanicOutOfBounds)); |
|
537 __ASSERT_DEBUG(rect.iTl.iY>=0 && rect.iBr.iY<=iSize.iHeight,Panic(EScreenDriverPanicOutOfBounds)); |
|
538 |
|
539 TUint32* pixelPtr = PixelAddress(rect.iTl.iX,rect.iTl.iY); |
|
540 TUint32* pixelRowPtrLimit = pixelPtr + (rect.Height() * iScanLineWords); |
|
541 |
|
542 TUint32* pixelRowPtr = pixelPtr; |
|
543 TUint32* pixelPtrLimit = pixelPtr + rect.Width(); |
|
544 |
|
545 if (iShadowMode & EFade) |
|
546 { |
|
547 while (pixelRowPtr < pixelRowPtrLimit) |
|
548 { |
|
549 TUint32* tempPixelPtr = pixelRowPtr; |
|
550 |
|
551 while (tempPixelPtr < pixelPtrLimit) |
|
552 { |
|
553 const TUint32 color = *tempPixelPtr; |
|
554 #if defined(SYMBIAN_USE_FAST_FADING) |
|
555 const TUint32 fast_fade_offset = NonPMA2PMAPixel((color & 0xff000000) | SYMBIAN_USE_FAST_FADING) & 0x00ffffff; |
|
556 *tempPixelPtr++ = (color & 0xff000000) | ((((color & 0x00ffffff) >> 1) & ~0x00808080) + fast_fade_offset); |
|
557 #else |
|
558 const TInt alpha = (color >> 24) + 1; |
|
559 const TUint32 fadeMapOffset = ((alpha * iFadeMapOffset) >> 8) & 0xff; |
|
560 const TUint32 wordFadeMapOffset = ((fadeMapOffset) << 16) | (fadeMapOffset); |
|
561 const TUint32 rb = ((((color & 0x00ff00ff) * iFadeMapFactor) >> 8) + wordFadeMapOffset) & 0x00ff00ff; |
|
562 const TUint32 g = ((((color & 0x0000ff00) * iFadeMapFactor) >> 16) + fadeMapOffset) << 8; |
|
563 *tempPixelPtr++ = (color & 0xff000000) | rb | g; |
|
564 #endif |
|
565 } |
|
566 pixelRowPtr += iScanLineWords; |
|
567 pixelPtrLimit += iScanLineWords; |
|
568 } |
|
569 } |
|
570 |
|
571 if (iShadowMode & EShadow) |
|
572 { |
|
573 pixelRowPtr = pixelPtr; |
|
574 pixelPtrLimit = pixelPtr + rect.Width(); |
|
575 |
|
576 while (pixelRowPtr < pixelRowPtrLimit) |
|
577 { |
|
578 TUint32* tempPixelPtr = pixelRowPtr; |
|
579 |
|
580 while (tempPixelPtr < pixelPtrLimit) |
|
581 { |
|
582 const TUint32 color = *tempPixelPtr; |
|
583 const TInt alpha = (color >> 24) + 1; |
|
584 const TInt uLimit = ((0x40) * alpha) >> 8; |
|
585 TInt r = (color >> 16) & 0xff; |
|
586 r = (r > uLimit) ? (r-uLimit) : 0; |
|
587 TInt g = (color >> 8) & 0xff; |
|
588 g = (g > uLimit) ? (g - uLimit) : 0; |
|
589 TInt b = color & 0xff; |
|
590 b = (b > uLimit) ? (b - uLimit) : 0; |
|
591 *tempPixelPtr++ = (color & 0xff000000) | (r << 16) | (g << 8) | b; |
|
592 } |
|
593 pixelRowPtr += iScanLineWords; |
|
594 pixelPtrLimit += iScanLineWords; |
|
595 } |
|
596 } |
|
597 } |
|
598 |
|
599 /** |
|
600 @see CFbsDrawDevice::WriteLine |
|
601 */ |
|
602 void CDrawThirtyTwoBppBitmapAlphaPM::WriteLine(TInt aX,TInt aY,TInt aLength,TUint32* aBuffer, |
|
603 CGraphicsContext::TDrawMode aDrawMode) |
|
604 { |
|
605 const TPoint originalPoint(aX,aY); |
|
606 DeOrientate(aX,aY);//aX and aY - physical coordinates |
|
607 |
|
608 __ASSERT_DEBUG(aX >= 0,Panic(EScreenDriverPanicOutOfBounds)); |
|
609 __ASSERT_DEBUG(aY >= 0,Panic(EScreenDriverPanicOutOfBounds)); |
|
610 #if defined(_DEBUG) |
|
611 switch (iOrientation) |
|
612 { |
|
613 case EOrientationNormal: |
|
614 __ASSERT_DEBUG(aX + aLength <= iSize.iWidth,Panic(EScreenDriverPanicOutOfBounds)); |
|
615 break; |
|
616 case EOrientationRotated90: |
|
617 __ASSERT_DEBUG(aY + aLength <= iSize.iHeight,Panic(EScreenDriverPanicOutOfBounds)); |
|
618 break; |
|
619 case EOrientationRotated180: |
|
620 __ASSERT_DEBUG(aX - aLength >= -1,Panic(EScreenDriverPanicOutOfBounds)); |
|
621 break; |
|
622 default: // EOrientationRotated270 |
|
623 __ASSERT_DEBUG(aY - aLength >= -1,Panic(EScreenDriverPanicOutOfBounds)); |
|
624 break; |
|
625 } |
|
626 #endif |
|
627 __ASSERT_DEBUG(aLength > 0,Panic(EScreenDriverPanicZeroLength)); |
|
628 __ASSERT_DEBUG(aBuffer,Panic(EScreenDriverPanicNullPointer)); |
|
629 |
|
630 MapBufferToUserDisplayMode(aLength,aBuffer); |
|
631 if(iShadowMode) |
|
632 { |
|
633 ShadowBuffer(aLength,aBuffer); |
|
634 } |
|
635 if(aDrawMode&CGraphicsContext::EInvertPen) |
|
636 { |
|
637 #if defined(_DEBUG) |
|
638 // code in CFbsBitGc::DoBitBltMasked() does not require logical operator pen modes in premultiplied alpha screen driver for blitting of icons with masks |
|
639 // RDebug::Printf("Premultiplied alpha mode invert pen behaviour not defined / implemented"); |
|
640 #endif |
|
641 // no-operation |
|
642 } |
|
643 if(aDrawMode&CGraphicsContext::EPenmode) |
|
644 { |
|
645 BlendLine(aX,aY,aLength,aBuffer); |
|
646 return; |
|
647 } |
|
648 if(aDrawMode&CGraphicsContext::EWriteAlpha) |
|
649 { |
|
650 CDrawThirtyTwoBppBitmapCommon::WriteLine(aX,aY,aLength,aBuffer); |
|
651 return; |
|
652 } |
|
653 if(aDrawMode&CGraphicsContext::EInvertScreen) |
|
654 { |
|
655 #if defined(_DEBUG) |
|
656 // RDebug::Printf("Premultiplied alpha mode invert screen behaviour not defined / implemented"); |
|
657 #endif |
|
658 return; //no-operation |
|
659 } |
|
660 if(aDrawMode&CGraphicsContext::EXor) |
|
661 { |
|
662 #if defined(_DEBUG) |
|
663 // code in CFbsBitGc::DoBitBltMasked() does not require logical operator pen modes in premultiplied alpha screen driver for blitting of icons with masks |
|
664 // RDebug::Printf("Premultiplied alpha mode XOR operation not defined / implemented"); |
|
665 #endif |
|
666 return; //no-operation |
|
667 } |
|
668 else if(aDrawMode&CGraphicsContext::EAnd) |
|
669 { |
|
670 #if defined(_DEBUG) |
|
671 // code in CFbsBitGc::DoBitBltMasked() does not require logical operator pen modes in premultiplied alpha screen driver for blitting of icons with masks |
|
672 // RDebug::Printf("Premultiplied alpha mode AND operation not defined / implemented"); |
|
673 #endif |
|
674 return; //no-operation |
|
675 } |
|
676 else if(aDrawMode&CGraphicsContext::EOr) |
|
677 { |
|
678 #if defined(_DEBUG) |
|
679 // RDebug::Printf("Premultiplied alpha mode OR operation not defined / implemented"); |
|
680 #endif |
|
681 return; //no-operation |
|
682 } |
|
683 } |
|
684 |
|
685 TRgb CDrawThirtyTwoBppBitmapAlphaPM::RgbColor(TUint32 aColor) const |
|
686 { |
|
687 return TRgb::_Color16MAP(aColor); |
|
688 } |
|
689 |
|
690 TUint32 CDrawThirtyTwoBppBitmapAlphaPM::Color(const TRgb& aColor) |
|
691 { |
|
692 return aColor._Color16MAP(); |
|
693 } |
|
694 |
|
695 TInt CDrawThirtyTwoBppBitmapAlphaPM::WriteRgbOutlineAndShadow(TInt aX, TInt aY, const TInt aLength, |
|
696 TUint32 aOutlinePenColor, TUint32 aShadowColor, |
|
697 TUint32 aFillColor, const TUint8* aDataBuffer) |
|
698 { |
|
699 const TUint alphaShifted = aOutlinePenColor & 0xff000000; |
|
700 const TUint alpha = alphaShifted>>24; |
|
701 if (alpha==0 || aLength<=0) |
|
702 return KErrNone; |
|
703 DeOrientate(aX,aY); |
|
704 TUint32* pixelPtr = PixelAddress(aX,aY); |
|
705 const TInt pixelPtrInc = PixelAddressIncrement(); |
|
706 const TUint8* dataBufferPtrLimit = aDataBuffer + aLength; |
|
707 TInt blendedRedColor; |
|
708 TInt blendedGreenColor; |
|
709 TInt blendedBlueColor; |
|
710 TUint8 index = 0; |
|
711 TUint32 finalColor; |
|
712 |
|
713 //Get red color. Equivalent to TRgb::Red() |
|
714 const TInt redOutlinePenColor = (aOutlinePenColor & 0xff0000) >> 16; |
|
715 const TInt redShadowColor = (aShadowColor & 0xff0000) >> 16; |
|
716 const TInt redFillColor = (aFillColor & 0xff0000) >> 16; |
|
717 |
|
718 //Get green color. Equivalent to TRgb::Green() |
|
719 const TInt greenOutlinePenColor = (aOutlinePenColor & 0xff00) >> 8; |
|
720 const TInt greenShadowColor = (aShadowColor & 0xff00) >> 8; |
|
721 const TInt greenFillColor = (aFillColor & 0xff00) >> 8; |
|
722 |
|
723 //Get blue color. Equivalent to TRgb::Blue() |
|
724 const TInt blueOutlinePenColor = aOutlinePenColor & 0xff; |
|
725 const TInt blueShadowColor = aShadowColor & 0xff; |
|
726 const TInt blueFillColor = aFillColor & 0xff; |
|
727 const TUint16* normTable = PtrTo16BitNormalisationTable(); |
|
728 |
|
729 // Calculate PMA values for aFillColor & aOutlinePenColor that we can use for fast blending in the simple cases |
|
730 // Don't pre calculate PMA version of aShadowColor as it is presumed not to be used enough to make this worthwhile |
|
731 const TUint32 pmaFillColor = NonPMA2PMAPixel((aFillColor&0x00FFFFFF)|alphaShifted); |
|
732 const TUint32 pmaOutlineColor = NonPMA2PMAPixel(aOutlinePenColor); |
|
733 while (aDataBuffer < dataBufferPtrLimit) |
|
734 { |
|
735 TUint backgroundAlpha; |
|
736 TUint outlineAlpha; |
|
737 TUint shadowAlpha; |
|
738 TUint fillAlpha; |
|
739 index = *aDataBuffer++; |
|
740 backgroundAlpha = FourColorBlendLookup[index][KBackgroundColorIndex]; |
|
741 if (backgroundAlpha == 255) |
|
742 { |
|
743 //background colour |
|
744 //No drawing required so move on to next pixel. |
|
745 pixelPtr += pixelPtrInc; |
|
746 continue; |
|
747 } |
|
748 fillAlpha=FourColorBlendLookup[index][KFillColorIndex]; |
|
749 if (fillAlpha == 255) |
|
750 { |
|
751 //Use fill colour to draw |
|
752 finalColor = pmaFillColor; |
|
753 oneColorBlend: |
|
754 if (alpha==0xFF) |
|
755 *pixelPtr=finalColor; |
|
756 else |
|
757 PMABlend_noChecksInplace(*pixelPtr, finalColor, alpha); |
|
758 pixelPtr += pixelPtrInc; |
|
759 continue; |
|
760 } |
|
761 outlineAlpha = FourColorBlendLookup[index][KOutlineColorIndex]; |
|
762 if (outlineAlpha == 255) |
|
763 { |
|
764 //Use outline colour to draw |
|
765 finalColor = pmaOutlineColor; |
|
766 goto oneColorBlend; |
|
767 } |
|
768 shadowAlpha = FourColorBlendLookup[index][KShadowColorIndex]; |
|
769 if (shadowAlpha == 255) |
|
770 { |
|
771 //Use shadow colour to draw |
|
772 finalColor = NonPMA2PMAPixel((aShadowColor&0x00FFFFFF)|alphaShifted); |
|
773 goto oneColorBlend; |
|
774 } |
|
775 blendedRedColor = redOutlinePenColor * outlineAlpha + |
|
776 redShadowColor * shadowAlpha + |
|
777 redFillColor * fillAlpha; |
|
778 |
|
779 blendedGreenColor = greenOutlinePenColor * outlineAlpha + |
|
780 greenShadowColor * shadowAlpha + |
|
781 greenFillColor * fillAlpha; |
|
782 |
|
783 blendedBlueColor = blueOutlinePenColor * outlineAlpha + |
|
784 blueShadowColor * shadowAlpha + |
|
785 blueFillColor * fillAlpha; |
|
786 if (backgroundAlpha) |
|
787 { |
|
788 const TUint32 backgroundColor = PMA2NonPMAPixel(*pixelPtr, normTable); |
|
789 blendedRedColor += ((backgroundColor & 0xff0000) >> 16) * backgroundAlpha; |
|
790 blendedGreenColor += ((backgroundColor & 0xff00) >> 8) * backgroundAlpha; |
|
791 blendedBlueColor += (backgroundColor & 0xff) * backgroundAlpha; |
|
792 } |
|
793 finalColor = ((blendedRedColor&0xFF00)<<8) | (blendedGreenColor&0xFF00) | (blendedBlueColor>>8); |
|
794 |
|
795 if (alpha==0xFF) |
|
796 *pixelPtr=finalColor|0xFF000000; |
|
797 else |
|
798 { |
|
799 //pre-multiply, inplace. |
|
800 finalColor = NonPMA2PMAPixel(finalColor|alphaShifted); |
|
801 PMABlend_noChecksInplace(*pixelPtr, finalColor, alpha); |
|
802 } |
|
803 pixelPtr += pixelPtrInc; |
|
804 } |
|
805 return KErrNone; |
|
806 } |