os/graphics/graphicsdeviceinterface/directgdiadaptation/swsrc/swdirectgdidrawresource.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200 (2014-06-10)
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     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 "directgdiadapter.h"
    17 #include "swdirectgdiengine.h"
    18 #include "swdirectgdiimagesourceimpl.h"
    19 #include "swdirectgdidriverimpl.h"
    20 #include <bitdrawinterfaceid.h>
    21 #include <e32cmn.h>
    22 #include <bitdraw.h>
    23 #include <bmalphablend.h>
    24 #include <graphics/directgdidrawablesource.h>
    25 #include <pixelformats.h>
    26 #include "pixelutil.h"
    27 
    28 /**
    29 Helper class to deal with the case of blending 32-bit MAP source into 16-bit target which is not 
    30 supported by screen driver CDrawSixteenBppBitmap implementation.
    31 
    32 @publishedPartner
    33 @prototype
    34 @deprecated
    35 */
    36 class TDrawDeviceWrapper
    37 	{
    38 public:
    39 	TDrawDeviceWrapper(CFbsDrawDevice* aDrawDevice, CGraphicsContext::TDrawMode aDrawMode);
    40 	inline void WriteLine(TInt aX, TInt aY, TInt aLength, TUint32* aBuffer, CGraphicsContext::TDrawMode aDrawMode);
    41 private:
    42 	inline TUint16 ConvertTo64K(TUint32 aColor);
    43 	inline TUint16 Blend16MapTo64K(TUint16 aDest, TUint32 aSrc);
    44 	void BlendLine16MapTo64K(TInt aX, TInt aY, TInt aLength, TUint32* aBuffer, CGraphicsContext::TDrawMode aDrawMode);
    45 	void OriginalWriteLine(TInt aX, TInt aY, TInt aLength, TUint32* aBuffer, CGraphicsContext::TDrawMode aDrawMode);
    46 
    47 private:
    48 	CFbsDrawDevice* iDrawDevice;
    49 	TUint32* iBits;
    50 
    51 	typedef void (TDrawDeviceWrapper::*TWriteLineFunc)(TInt,TInt,TInt,TUint32*,CGraphicsContext::TDrawMode);
    52 	TWriteLineFunc iWriteLineFunc;
    53 	};
    54 
    55 TDrawDeviceWrapper::TDrawDeviceWrapper(CFbsDrawDevice* aDrawDevice, CGraphicsContext::TDrawMode aDrawMode):
    56 	iDrawDevice(aDrawDevice)
    57 	{
    58 	TAny* interface = NULL;
    59 	TInt err = iDrawDevice->GetInterface(KFastBlit2InterfaceID, interface);
    60 	// interface is guaranted to exist for 16-bit and 32-bit draw device
    61 	GRAPHICS_ASSERT_DEBUG(err == KErrNone, EDirectGdiPanicUnexpectedError);
    62 
    63 	iBits = (TUint32*) reinterpret_cast<MFastBlit2*>(interface)->Bits();
    64 	
    65 	// setup which funtion to call here rather tha making decision inside WriteLine which is usually called within
    66 	// a tight scanline loop
    67 	iWriteLineFunc = iDrawDevice->DisplayMode() == EColor64K && aDrawMode == CGraphicsContext::EDrawModePEN ? 
    68 			&TDrawDeviceWrapper::BlendLine16MapTo64K : &TDrawDeviceWrapper::OriginalWriteLine;
    69 	}
    70 
    71 inline void TDrawDeviceWrapper::WriteLine(TInt aX, TInt aY, TInt aLength, TUint32* aBuffer, CGraphicsContext::TDrawMode aDrawMode)
    72 	{
    73 	// calling member functions via pointer to member functions i.e.
    74 	// (object.*member_fn)(arg)
    75 	//
    76 	(this->*iWriteLineFunc)(aX, aY, aLength, aBuffer, aDrawMode);
    77 	}
    78 
    79 void TDrawDeviceWrapper::OriginalWriteLine(TInt aX, TInt aY, TInt aLength, TUint32* aBuffer, CGraphicsContext::TDrawMode aDrawMode)
    80 	{
    81 	iDrawDevice->WriteLine(aX, aY, aLength, aBuffer, aDrawMode);
    82 	}
    83 
    84 void TDrawDeviceWrapper::BlendLine16MapTo64K(TInt aX, TInt aY, TInt aLength, TUint32* aBuffer, CGraphicsContext::TDrawMode)
    85 	{
    86 	TUint16* pixelPtr = reinterpret_cast<TUint16*>(iBits);
    87 	pixelPtr += (aY * iDrawDevice->LongWidth()) + aX;
    88 	const TUint32* bufferPtr = aBuffer;
    89 	const TUint32* bufferPtrLimit = bufferPtr + aLength;
    90 
    91 	while (bufferPtr < bufferPtrLimit)
    92 		{
    93 		*pixelPtr = Blend16MapTo64K(*pixelPtr, *bufferPtr);
    94 		++bufferPtr;
    95 		++pixelPtr;
    96 		}
    97 	}
    98 
    99 inline TUint16 TDrawDeviceWrapper::ConvertTo64K(TUint32 aSrc)
   100 	{
   101 	TInt col = (aSrc & 0x0000f8) >> 3;
   102 	col |= (aSrc & 0x00fc00) >> 5;
   103 	col |= (aSrc & 0xf80000) >> 8;
   104 	
   105 	return col;
   106 	}
   107 	
   108 inline TUint16 TDrawDeviceWrapper::Blend16MapTo64K(TUint16 aDst, TUint32 aSrc)
   109 	{
   110 	const TInt alpha = aSrc >> 24;
   111 
   112 	if(alpha == 0x00)
   113 		{
   114 		return aDst;
   115 		}
   116 
   117 	if (alpha == 0xff)
   118 		{
   119 		return ConvertTo64K(aSrc);
   120 		}
   121 
   122 	// extract source components from 16MAP
   123 	const TInt src_rb = aSrc & 0x00ff00ff;
   124 	const TInt src_g = aSrc & 0x0000ff00;
   125 	const TInt oneMinusAlpha = 0x0100 - alpha;
   126 
   127 	// extract destination components from 64K format
   128     TInt dr = (aDst & 0xf800) >> 8;
   129     dr += dr >> 5;
   130     TInt dg = (aDst & 0x07e0) >> 3;
   131     dg += dg >> 6;
   132     TInt db = (aDst & 0x001f) << 3;
   133     db += db >> 5;
   134 
   135 	// combine red and blue components into a word to combine mult in one go
   136 	TInt dst_rb = (dr << 16) | db;
   137 	TInt dst_g = dg << 8;
   138 
   139 	// dst and src are in pre-multiplied format (64K can be treated both as pre or non-pre)
   140 	// dst = src + (1-alpha) * dst
   141 	//
   142 	dst_rb = (src_rb + ((oneMinusAlpha * dst_rb) >> 8)) & 0x00ff00ff;
   143 	dst_g = (src_g + ((oneMinusAlpha * dst_g) >> 8)) & 0x0000ff00;
   144 	
   145 	const TUint32 argb = 0xff000000 | dst_rb | dst_g;
   146 	return ConvertTo64K(argb);
   147 	}
   148 
   149 //
   150 // implements MDirectGdiEngine interfaces
   151 //
   152 
   153 /**
   154 @see MDirectGdiEngine::DrawResource(const TRect&,const RDirectGdiDrawableSource&,const TDesC8&)
   155 */
   156 void CSwDirectGdiEngine::DrawResource(
   157 		const TRect& aDestRect,
   158 		const RDirectGdiDrawableSource& aSource,
   159 		const TDesC8& /*aParam*/)
   160 	{
   161 	// DirectGDI reference implementation only support pixel based resource
   162 	// see CSwDirectGdiDriverImpl::CreateDrawableSource()
   163 	//
   164 	CSwDirectGdiImageSourceImpl* imgSrc = NULL;
   165 	TSize imgSize;
   166 	if (CheckImageSource(aSource.Handle(), imgSrc, &imgSize) != KErrNone)
   167 		{
   168 		return;
   169 		}
   170 
   171 	// drawing resource unscaled with no rotation
   172 	//
   173 	DrawResourceCommon(aDestRect, imgSrc, TRect(TPoint(0,0), imgSize), DirectGdi::EGraphicsRotationNone);
   174 	}
   175 
   176 /**
   177 @see MDirectGdiEngine::DrawResource(const TPoint&,const RDirectGdiDrawableSource&,DirectGdi::TGraphicsRotation)
   178 */
   179 void CSwDirectGdiEngine::DrawResource(const TPoint& aPos,
   180 		const RDirectGdiDrawableSource& aSource,
   181 		DirectGdi::TGraphicsRotation aRotation)
   182 	{
   183 	CSwDirectGdiImageSourceImpl* imgSrc = NULL;
   184 	TSize imgSize;
   185 	if (CheckImageSource(aSource.Handle(), imgSrc, &imgSize) != KErrNone)
   186 		{
   187 		return;
   188 		}
   189 
   190 	// drawing resource unscaled
   191 	//
   192 	// rotation will be applied before scaling, we must create destination rectangle 
   193 	// that match the size of rotated image
   194 
   195 	TRect destRect(aPos, imgSize);
   196 	if (aRotation==DirectGdi::EGraphicsRotation90 || aRotation==DirectGdi::EGraphicsRotation270)
   197 		{
   198 		// keep the top left corner in the same position but swap width and height
   199 		destRect.SetWidth(imgSize.iHeight);
   200 		destRect.SetHeight(imgSize.iWidth);
   201 		}
   202 
   203 	DrawResourceCommon(destRect, imgSrc, TRect(TPoint(0,0), imgSize), aRotation);
   204 	}
   205 
   206 /**
   207 @see MDirectGdiEngine::DrawResource(const TRect&,const RDirectGdiDrawableSource&,DirectGdi::TGraphicsRotation)
   208 */
   209 void CSwDirectGdiEngine::DrawResource(const TRect& aDestRect,
   210 		const RDirectGdiDrawableSource& aSource,
   211 		DirectGdi::TGraphicsRotation aRotation)
   212 	{
   213 	// aDestRect is not empty when we reach here
   214 	//
   215 	CSwDirectGdiImageSourceImpl* imgSrc = NULL;
   216 	TSize imgSize;
   217 	if (CheckImageSource(aSource.Handle(), imgSrc, &imgSize) != KErrNone)
   218 		{
   219 		return;
   220 		}
   221 
   222 	DrawResourceCommon(aDestRect, imgSrc, TRect(TPoint(0,0), imgSize), aRotation);
   223 	}
   224 
   225 /**
   226 @see MDirectGdiEngine::DrawResource(const TRect&,const RDirectGdiDrawableSource&,const TRect&,DirectGdi::TGraphicsRotation)
   227 */
   228 void CSwDirectGdiEngine::DrawResource(
   229 		const TRect& aDestRect,				
   230 		const RDirectGdiDrawableSource& aSource, 
   231 		const TRect& aSrcRect,
   232 		DirectGdi::TGraphicsRotation aRotation)
   233 	{
   234 	// pre:
   235 	// aDestRect and aSrcRect are not empty
   236 	//
   237 	CSwDirectGdiImageSourceImpl* imgSrc = NULL;
   238 	TSize imgSize;
   239 	if (CheckImageSource(aSource.Handle(), imgSrc, &imgSize) != KErrNone)
   240 		{
   241 		return;
   242 		}
   243 
   244 	// check source rectangle is fully contained within the image resource extent
   245 	if (aSrcRect.iTl.iX < 0 ||
   246 		aSrcRect.iTl.iY < 0 ||
   247 		aSrcRect.iBr.iX > imgSize.iWidth ||
   248 		aSrcRect.iBr.iY > imgSize.iHeight)
   249 		{
   250 		iDriver->SetError(KErrArgument);
   251 		return;
   252 		}   	
   253 	
   254 	DrawResourceCommon(aDestRect, imgSrc, aSrcRect, aRotation);
   255 	}
   256 
   257 //
   258 // internal functions
   259 //
   260 /**
   261 Checks image resource is fully constructed and registered with the driver.
   262 
   263 @param  aHandle A valid handle to an image source.
   264 @param  aImg On return, contains the image source.
   265 @param  aSize If not NULL, will contain the dimensions of the image source.
   266 @return KErrNone if successful, KErrBadHandle if aHandle is not a valid handle to an image source.
   267 */
   268 TInt CSwDirectGdiEngine::CheckImageSource(TInt aHandle, CSwDirectGdiImageSourceImpl*& aImg, TSize* aSize)
   269 	{
   270 	// check image exist
   271 	if (!iDriver->ValidImageSource(aHandle))
   272 		{
   273 		// replace KErrNotFound
   274 		const TInt err = KErrBadHandle;
   275 		iDriver->SetError(err);
   276 		return err;
   277 		}
   278 	
   279 	aImg = reinterpret_cast<CSwDirectGdiImageSourceImpl*>(aHandle);
   280 
   281 	// RSgImage cannot be created with zero size, so there is no point in validating its size and
   282 	// simply return image size if requested
   283 	if (aSize)
   284 		{		
   285 		*aSize = aImg->Size();
   286 		}
   287 
   288 	return KErrNone;
   289 	}
   290 
   291 /**
   292 Implements common DrawResource() functionality used by all DrawResource() variants.
   293 */
   294 void CSwDirectGdiEngine::DrawResourceCommon(
   295 		const TRect& aDestRect,
   296 		const CSwDirectGdiImageSourceImpl* aImg,
   297 		const TRect& aSrcRect,
   298 		DirectGdi::TGraphicsRotation aRotation)
   299 	{
   300 	// pre:
   301 	// aDestRect and aSrcRect are not empty
   302 	// aSrcRect is within the image extent
   303 	//
   304 	// translate relative coord to target absolute coord system
   305 	TRect destRectAbs(aDestRect);
   306 	destRectAbs.Move(iOrigin);
   307 
   308 	// check whether we need to blend or write
   309 	const TBool opaqueSource = (!PixelFormatUtil::HasAlpha(aImg->PixelFormat())) && (iDrawMode == DirectGdi::EDrawModePEN);
   310 	if (opaqueSource)
   311 		{
   312 		iDrawMode = DirectGdi::EDrawModeWriteAlpha;
   313 		}
   314 
   315 	// repeat drawing op for each rectangle in the clipping region
   316 	const TInt numOfRects = iDefaultRegionPtr->Count();	
   317 	for (TInt idx = 0; idx < numOfRects; ++idx)
   318 		{
   319 		TRect clipRectAbs = (*iDefaultRegionPtr)[idx];
   320 		if (!clipRectAbs.Intersects(destRectAbs))
   321 			{
   322 			continue;
   323 			}
   324 
   325 		// intersect current clip rect with dest rect to get actual draw area
   326 		clipRectAbs.Intersection(destRectAbs);
   327 		DoDrawResource(destRectAbs, aImg, aSrcRect, aRotation, clipRectAbs);
   328 
   329 		iDrawDevice->UpdateRegion(clipRectAbs);
   330 		}
   331 	
   332 	if (opaqueSource)
   333 		{
   334 		iDrawMode = DirectGdi::EDrawModePEN;
   335 		}	
   336 	}
   337 
   338 /**
   339 Rotate a given rectangle 90 degree clockwise around the specified origin.
   340 */
   341 void CSwDirectGdiEngine::Rotate90(TRect& aRect, const TPoint& aOrigin)
   342 	{
   343 	// rotated bottom-left become top-left of rotated rect
   344 	//
   345 	TPoint bl(aRect.iTl.iX, aRect.iBr.iY);
   346 	const TInt w = aRect.Width();
   347 	const TInt h = aRect.Height();
   348 	
   349 	const TPoint dbl = bl - aOrigin;
   350 	bl.iX = aOrigin.iX - dbl.iY;
   351 	bl.iY = aOrigin.iY + dbl.iX;
   352 
   353 	aRect = TRect(bl, TSize(h,w));
   354 	}
   355 
   356 /**
   357 Rotate a given rectangle 180 degree clockwise around the specified origin.
   358 */
   359 void CSwDirectGdiEngine::Rotate180(TRect& aRect, const TPoint& aOrigin)
   360 	{
   361 	// rotated bottom-right become top-left of rotated rect
   362 	//
   363 	TPoint br(aRect.iBr);
   364 	const TSize sz = aRect.Size();
   365 
   366 	const TPoint dbr = br - aOrigin;
   367 	br.iX = aOrigin.iX - dbr.iX;
   368 	br.iY = aOrigin.iY - dbr.iY;
   369 
   370 	aRect = TRect(br, sz);
   371 	}
   372 
   373 /**
   374 Rotate a given rectangle 270 degree clockwise around the specified origin.
   375 */
   376 void CSwDirectGdiEngine::Rotate270(TRect& aRect, const TPoint& aOrigin)
   377 	{
   378 	// rotated top-right become top-left of rotated rect
   379 	//
   380 	TPoint tr(aRect.iBr.iX, aRect.iTl.iY);
   381 	const TInt w = aRect.Width();
   382 	const TInt h = aRect.Height();
   383 	
   384 	const TPoint dtr = tr - aOrigin;
   385 	tr.iX = aOrigin.iX + dtr.iY;
   386 	tr.iY = aOrigin.iY - dtr.iX;
   387 
   388 	aRect = TRect(tr, TSize(h,w));
   389 	}
   390 
   391 /**
   392 Tests that the size of a given rotated rectangle match the image source extent.
   393 */
   394 TBool CSwDirectGdiEngine::RotatedSizeMatch(const TRect& aDst, const TRect& aSrc, DirectGdi::TGraphicsRotation aRot)
   395 	{
   396 	if (aRot==DirectGdi::EGraphicsRotationNone || aRot==DirectGdi::EGraphicsRotation180)
   397 		{
   398 		return aDst.Size()==aSrc.Size();
   399 		}
   400 	else
   401 		{
   402 		return aDst.Width()==aSrc.Height() && aDst.Height()==aSrc.Width();
   403 		}
   404 	}
   405 
   406 /**
   407 Draws a rectangular area of resource and apply rotation and/or scaling if requested.
   408 */
   409 void CSwDirectGdiEngine::DoDrawResource(
   410 		const TRect& aDestRectAbs,
   411 		const CSwDirectGdiImageSourceImpl* aImg,
   412 		const TRect& aSrcRect,
   413 		DirectGdi::TGraphicsRotation aRotation,
   414 		const TRect& aClipRectAbs)
   415 	{
   416 	// pre:
   417 	// SetClippingRegion() already check that clipping region is always contained
   418 	// within device full extent.
   419 
   420 	// check src rect match the size of rotated dest rect
   421 	if (RotatedSizeMatch(aDestRectAbs, aSrcRect, aRotation))
   422 		{
   423 		// aClipRect is the effective drawing clipped area, it has been intersected with dest rect by the
   424 		// calling function/DoDrawResourceCommon() and it is not empty when we reach here
   425 
   426 		// image size has been checked at the top level DrawResource() no need to check it again
   427 
   428 		// use aClipRect to determine how much area should be read from the image and transform
   429 		// the effective read area into source rect depending on rotation parameter
   430 		
   431 		// start with aClipRect
   432 		TRect xformSrcRect(aClipRectAbs);
   433 		switch (aRotation)
   434 			{
   435 			case DirectGdi::EGraphicsRotationNone:
   436 				// align top-left corner of dest rect with top-left corner of src rect
   437 				xformSrcRect.Move(aSrcRect.iTl - aDestRectAbs.iTl);
   438 				break;
   439 			case DirectGdi::EGraphicsRotation90:
   440 				{
   441 				// align top-right corner of dest rect with top-left corner of src rect
   442 				xformSrcRect.Move(aSrcRect.iTl - TPoint(aDestRectAbs.iBr.iX, aDestRectAbs.iTl.iY));
   443 				// rotate 270 (-90) degree using top-left corner of src rect as pivot point
   444 				Rotate270(xformSrcRect, aSrcRect.iTl);
   445 				}
   446 				break;
   447 			case DirectGdi::EGraphicsRotation180:
   448 				{
   449 				// align bottom-right corner of dest rect with top-left corner of src rect
   450 				xformSrcRect.Move(aSrcRect.iTl - aDestRectAbs.iBr);
   451 				// rotate 180 (-180) degree using top-left corner of src rect as pivot point
   452 				Rotate180(xformSrcRect, aSrcRect.iTl);
   453 				}
   454 				break;
   455 			case DirectGdi::EGraphicsRotation270:
   456 				{
   457 				// align bottom-left corner of dest rect with top-left corner of src rect
   458 				xformSrcRect.Move(aSrcRect.iTl - TPoint(aDestRectAbs.iTl.iX, aDestRectAbs.iBr.iY));
   459 				// rotate 90 (-270) degree using top-left corner of src rect as pivot point
   460 				Rotate90(xformSrcRect, aSrcRect.iTl);
   461 				}
   462 				break;
   463 
   464 			// no need for extra check, aRotation has been checked at generic layer
   465 			}
   466 
   467 		DoBlitResource(aClipRectAbs.iTl, aImg, xformSrcRect, aRotation);
   468 		return;
   469 		}
   470 
   471 	DoScaledBlitResource(aDestRectAbs, aImg, aSrcRect, aRotation, aClipRectAbs);
   472 	}
   473 
   474 /**
   475 Draws a rectangular area of resource rotated with no scaling.
   476 @panic DGDIAdapter 1009, if the pixel format of the draw device is unknown (debug only). 
   477 */
   478 void CSwDirectGdiEngine::DoBlitResource(
   479 		const TPoint& aDest,
   480 		const CSwDirectGdiImageSourceImpl* aImg,
   481 		const TRect& aSrcRect,
   482 		DirectGdi::TGraphicsRotation aRotation)
   483 	{		
   484 	// pre:
   485 	// aDest is the top-left of clipped destination rectangle i.e. intersection of user destination
   486 	// rectangle with current clipping rect
   487 	// aSrcRect is rotated clipped read area i.e. effective read area with respect to original 
   488 	// image orientation i.e.it no longer represents user specified source rect.
   489 
   490 	// no need to do extra check on parameters here because:
   491 	// aDest is guaranteed to be within device drawing area
   492 	// aSrcRect is guaranteed to be within image source area
   493 	
   494 	const TUidPixelFormat devFormat = PixelFormatUtil::ConvertToPixelFormat(iDrawDevice->DisplayMode());
   495 	GRAPHICS_ASSERT_DEBUG(devFormat != EUidPixelFormatUnknown, EDirectGdiPanicInvalidDisplayMode);
   496 
   497 	const TUidPixelFormat imgFormat = aImg->PixelFormat();
   498 	const TUint32* imgAddr = reinterpret_cast<TUint32*>(aImg->DataBuffer());
   499 	const TInt imgStride = aImg->Stride();
   500 	const TSize imgSize = aImg->Size();
   501 	const CGraphicsContext::TDrawMode drawMode = GcDrawMode(iDrawMode);
   502 	
   503 	const TInt width = aSrcRect.Width();
   504 	const TInt height = aSrcRect.Height();
   505 	// write scanline starting from top dest row
   506 	TInt destY = aDest.iY;
   507 	// setup pixel reader toolkit
   508 	TPixelBufferReader reader(imgAddr, imgSize, imgStride, imgFormat);
   509 	TDrawDeviceWrapper writer(iDrawDevice, GcDrawMode(iDrawMode));
   510 	
   511 	//
   512 	// special case when rotation is none
   513 	//
   514 	if (aRotation == DirectGdi::EGraphicsRotationNone)
   515 		{
   516 		TAny* interface = NULL;
   517 	
   518 		// source and destination format match and using write alpha mode i.e. reduce blit to memcpy
   519 		if (iDrawMode == DirectGdi::EDrawModeWriteAlpha && devFormat == imgFormat)
   520 			{
   521 			TInt err = iDrawDevice->GetInterface(KFastBlit2InterfaceID, interface);
   522 			if (err == KErrNone)
   523 				{
   524 				GRAPHICS_ASSERT_DEBUG(interface, EDirectGdiPanicInvalidPointer);
   525 				MFastBlit2* fblit = static_cast<MFastBlit2*>(interface);
   526 				err = fblit->WriteBitmapBlock(aDest, imgAddr, imgStride, imgSize, aSrcRect);
   527 				if (err == KErrNone)
   528 					{
   529 					return;
   530 					}
   531 				}
   532 			}
   533 
   534 		// fallback from MFastBlit2  when source and destination format match. 
   535 		// Note that there was previously an optimization added here that used MFlastBlend if 
   536 		// available, however it did not work correctly for some cases using DrawResource so has been 
   537 		// removed from this code. (A source drawn with OpenGLES on to a target in XRGB_8888 format
   538 		// actually had alpha in the unused channel which was being drawn by MFastBlend)
   539 		if (devFormat == imgFormat)
   540 			{
   541 			for (TInt row=aSrcRect.iTl.iY; row<aSrcRect.iBr.iY; ++row,++destY)
   542 				{
   543 				const TPoint pos(aSrcRect.iTl.iX, row);
   544 				const TUint32* slptr = reader.GetPixelAddr(pos);
   545 				writer.WriteLine(aDest.iX, destY, width, const_cast<TUint32*>(slptr), drawMode);
   546 				}
   547 			
   548 			return;
   549 			}
   550 
   551 		// there is one additional case that can be optimised by eleminating copy when:
   552 		// rotation : none
   553 		// scaling 	: none
   554 		// dst		: opaque
   555 		// src		: has alpha and premultiplied
   556 		// mode 	: PEN
   557 		}
   558 
   559 	//
   560 	// generic cases
   561 	//
   562 	// copying is necessary either to convert pixel format or to read back buffer in reverse order 
   563 	// to achieve rotation
   564 	//
   565 	const TInt scanLineBytes = iDrawDevice->ScanLineBytes();
   566 	TUint32* scanLineBuffer = iDrawDevice->ScanLineBuffer();
   567 	TPtr8 scanLineDes(reinterpret_cast<TUint8*>(scanLineBuffer),scanLineBytes,scanLineBytes);
   568 
   569 	// if destination is opaque e.g. RGB_565, XRGB_8888 and the source has alpha, it shall blend
   570 	// (because iDrawMode is set to WritePEN)
   571 	// we treat opaque destination as in pre-multiplied format (with alpha value 1), and read the 
   572 	// source in pre-multiplied format too, to enable optimum blending computation i.e.
   573 	// "src + (1-alpha) * dst"
   574 	const TUidPixelFormat readFormat = !PixelFormatUtil::HasAlpha(devFormat) &&
   575 							iDrawMode == DirectGdi::EDrawModePEN ?
   576 							EUidPixelFormatARGB_8888_PRE : devFormat;
   577 
   578 	if (aRotation == DirectGdi::EGraphicsRotationNone)
   579 		{
   580 		// general fallback from FastBlendBitmap
   581 		//
   582 		const TInt readLen = width;
   583 		// normal read scanline, left to right
   584 		//
   585 		for (TInt row=aSrcRect.iTl.iY; row<aSrcRect.iBr.iY; ++row,++destY)
   586 			{
   587 			const TPoint pos(aSrcRect.iTl.iX, row);
   588 			reader.GetScanLine(scanLineDes,pos, readLen, readFormat, TPixelBufferReader::EReadHorizontal);
   589 			writer.WriteLine(aDest.iX, destY, readLen, scanLineBuffer, drawMode);
   590 			}
   591 		}
   592 	else if (aRotation == DirectGdi::EGraphicsRotation90)
   593 		{
   594 		const TInt readLen = height;
   595 		// read scanline vertically from bottom to up, and from the lef-most column
   596 		//
   597 		for (TInt col=aSrcRect.iTl.iX; col<aSrcRect.iBr.iX; ++col,++destY)
   598 			{
   599 			const TPoint pos(col, aSrcRect.iBr.iY-1);
   600 			reader.GetScanLine(scanLineDes, pos, readLen, readFormat, TPixelBufferReader::EReadVerticalReverse);
   601 			writer.WriteLine(aDest.iX, destY, readLen, scanLineBuffer, drawMode);
   602 			}
   603 		}
   604 	else if (aRotation == DirectGdi::EGraphicsRotation180)
   605 		{
   606 		const TInt readLen = width;
   607 		// read scanline from right to left, starting from the most bottom scanline
   608 		//
   609 		for (TInt row=aSrcRect.iBr.iY-1; row>=aSrcRect.iTl.iY; --row,++destY)
   610 			{
   611 			const TPoint pos(aSrcRect.iBr.iX-1, row);
   612 			reader.GetScanLine(scanLineDes, pos, readLen, readFormat, TPixelBufferReader::EReadHorizontalReverse);
   613 			writer.WriteLine(aDest.iX, destY, readLen, scanLineBuffer, drawMode);
   614 			}
   615 		}
   616 	else if (aRotation == DirectGdi::EGraphicsRotation270)
   617 		{
   618 		const TInt readLen = height;
   619 		// read scanline vertically top to bottom, and from the right-most column
   620 		//
   621 		for (TInt col=aSrcRect.iBr.iX-1; col>=aSrcRect.iTl.iX; --col,++destY)
   622 			{
   623 			const TPoint pos(col, aSrcRect.iTl.iY);
   624 			reader.GetScanLine(scanLineDes, pos, readLen, readFormat, TPixelBufferReader::EReadVertical);
   625 			writer.WriteLine(aDest.iX, destY, readLen, scanLineBuffer, drawMode);
   626 			}
   627 		}
   628 	}
   629 
   630 /**
   631 Draws a rectangular area of resource rotated and/or scaled up/down.
   632 @panic DGDIAdapter 1009, if the pixel format of the draw device is unknown (debug only).
   633 */
   634 void CSwDirectGdiEngine::DoScaledBlitResource(
   635 		const TRect& aDestRectAbs,
   636 		const CSwDirectGdiImageSourceImpl* aImg,
   637 		const TRect& aSrcRect,
   638 		DirectGdi::TGraphicsRotation aRotation,
   639 		const TRect& aClipRectAbs)
   640 	{
   641 	// pre:
   642 	// aDestRectAbs is the user specified dest rect that has been translated to target coord system. It may
   643 	// be larger/outside the target drawing area. We must not modify this rect as it will be used to
   644 	// determine the scaling factor.
   645 	// aSrcRect is the user specified src rect, it is within the image extent.
   646 	// aClipRectAbs is the intersection of current clipping rect and aDestRectAbs and is within the
   647 	// target drawing area.
   648 
   649 	const TUidPixelFormat devFormat = PixelFormatUtil::ConvertToPixelFormat(iDrawDevice->DisplayMode());
   650 	GRAPHICS_ASSERT_DEBUG(devFormat != EUidPixelFormatUnknown, EDirectGdiPanicInvalidDisplayMode);
   651 
   652 	const TUint32* imgAddr = reinterpret_cast<TUint32*>(aImg->DataBuffer());
   653 	const TInt imgStride = aImg->Stride();
   654 	const TSize imgSize = aImg->Size();
   655 	const TUidPixelFormat imgFormat = aImg->PixelFormat();
   656 	const CGraphicsContext::TDrawMode drawMode = GcDrawMode(iDrawMode);
   657 
   658 	// if destination is opaque e.g. RGB_565, XRGB_8888 and the source has alpha, it shall blend
   659 	// (because iDrawMode is set to WritePEN)
   660 	// we treat opaque destination as in pre-multiplied format (with alpha value 1), and read the 
   661 	// source in pre-multiplied format too, to enable optimum blending computation i.e.
   662 	// "src + (1-alpha) * dst"
   663 	const TUidPixelFormat readFormat = !PixelFormatUtil::HasAlpha(devFormat) &&
   664 							iDrawMode == DirectGdi::EDrawModePEN ?
   665 							EUidPixelFormatARGB_8888_PRE : devFormat;
   666 
   667 	TUint32* scanLineBuffer = iDrawDevice->ScanLineBuffer();
   668 	const TInt scanLineBytes = iDrawDevice->ScanLineBytes();
   669 	TPtr8 scanLineDes(reinterpret_cast<TUint8*>(scanLineBuffer), scanLineBytes, scanLineBytes);
   670 
   671 	// setup pixel reader toolkit
   672 	//
   673 	TPixelBufferReader reader(imgAddr, imgSize, imgStride, imgFormat);
   674 	TDrawDeviceWrapper writer(iDrawDevice, GcDrawMode(iDrawMode));
   675 
   676 	if (aRotation == DirectGdi::EGraphicsRotationNone)
   677 		{		
   678 		// Note that there was previously an optimization added here that used MFlastBlend if 
   679 		// available, however it did not work correctly for some cases using DrawResource so has been 
   680 		// removed from this code. (A source drawn with OpenGLES on to a target in XRGB_8888 format
   681 		// actually had alpha in the unused channel which was being drawn by MFastBlend)
   682 		//
   683 		const TInt srcLen = aSrcRect.Width();
   684 		const TInt destLen = aDestRectAbs.Width();
   685 		const TInt clipLen = aClipRectAbs.Width();
   686 		const TInt clipPos = aClipRectAbs.iTl.iX - aDestRectAbs.iTl.iX;
   687 
   688 		// setup DDA for scaling in Y direction based on src rect and dst rect size
   689 		// scaling in X direction will be done by GetScaledScanLine()
   690 		//
   691 		// setup Y scaler and start from top-left of src/dest to bottom-right of src/dest
   692 		
   693 		TLinearDDA yScaler;
   694 		yScaler.Construct(
   695 				TPoint(aSrcRect.iTl.iY, aDestRectAbs.iTl.iY),
   696 				TPoint(aSrcRect.iBr.iY, aDestRectAbs.iBr.iY),
   697 				TLinearDDA::ELeft);
   698 
   699 		// move to position of current clip rect top row as the start of dest Y
   700 		TInt srcY;	
   701 		yScaler.JumpToYCoord2(srcY, aClipRectAbs.iTl.iY);
   702 
   703 		// yPos contains mapping between src Y (TPoint.iX) and dest Y (TPoint.iY)
   704 		TPoint yPos(srcY, aClipRectAbs.iTl.iY);
   705 
   706 		// write to target from top to bottom
   707 		//
   708 		while (yPos.iY < aClipRectAbs.iBr.iY)
   709 			{
   710 			reader.GetScaledScanLine(scanLineDes,
   711 									TPoint(aSrcRect.iTl.iX, yPos.iX),	// src X and Y
   712 									clipPos,							// clipped dest X
   713 									clipLen,
   714 									destLen,
   715 									srcLen,
   716 									readFormat,
   717 									TPixelBufferReader::EReadHorizontal);
   718 			
   719 			// use dest Y here
   720 			writer.WriteLine(aClipRectAbs.iTl.iX, yPos.iY, clipLen, scanLineBuffer, drawMode);
   721 
   722 			// move scaler one position
   723 			yScaler.NextStep(yPos);
   724 			};
   725 		}
   726 	else if (aRotation == DirectGdi::EGraphicsRotation90)
   727 		{
   728 		// we're going to read source vertically from bottom to up, swap relevant bits and pieces
   729 		// dst-width corresponds to src-height
   730 		// dst-height corresponds to src-width
   731 		//
   732 		const TInt srcLen = aSrcRect.Height();
   733 		const TInt destLen = aDestRectAbs.Width();
   734 
   735 		// the following doesn't change, the amount of pixel read (vertically) will be based on
   736 		// the drawing area witdh i.e. clip width
   737 		//
   738 		const TInt clipLen = aClipRectAbs.Width();
   739 
   740 		// offset into read area doesn't change either, it will be translated into some Y position
   741 		// from bottom row of source image
   742 		const TInt clipPos = aClipRectAbs.iTl.iX - aDestRectAbs.iTl.iX;
   743 
   744 		// setup DDA for scaling in src X direction based on src rect and dst rect size
   745 		// scaling in src Y direction will be done by GetScaledScanLine(EReadVerticalReverse)
   746 		//
   747 		// scaler map dest Y to src X because of 90 degre rotation
   748 		// start from  top row dest, left-most column src to bottom row dest, right-most column src
   749 		//
   750 		TLinearDDA xScaler;
   751 		xScaler.Construct(
   752 				TPoint(aSrcRect.iTl.iX, aDestRectAbs.iTl.iY),
   753 				TPoint(aSrcRect.iBr.iX, aDestRectAbs.iBr.iY),
   754 				TLinearDDA::ELeft);
   755 		
   756 		// move to position of current clip rect top row as the start of src X
   757 		TInt srcX;	
   758 		xScaler.JumpToYCoord2(srcX, aClipRectAbs.iTl.iY);
   759 
   760 		// xPos contains mapping between src X (TPoint.iX) and dest Y (TPoint.iY)
   761 		TPoint xPos(srcX, aClipRectAbs.iTl.iY);
   762 
   763 		// write to target from top to bottom
   764 		//
   765 		while (xPos.iY < aClipRectAbs.iBr.iY)
   766 			{
   767 			// read pixel vertically from left column to right
   768 			reader.GetScaledScanLine(scanLineDes,
   769 									TPoint(xPos.iX, aSrcRect.iBr.iY - 1),	// src X, src Y
   770 									clipPos,								// distance from bottom source
   771 									clipLen,
   772 									destLen,
   773 									srcLen,
   774 									readFormat,
   775 									TPixelBufferReader::EReadVerticalReverse);
   776 			
   777 			// use dest Y here
   778 			writer.WriteLine(aClipRectAbs.iTl.iX, xPos.iY, clipLen, scanLineBuffer, drawMode);
   779 
   780 			// move scaler one position
   781 			xScaler.NextStep(xPos);
   782 			}
   783 		}
   784 	else if (aRotation == DirectGdi::EGraphicsRotation180)
   785 		{
   786 		const TInt srcLen = aSrcRect.Width();
   787 		const TInt destLen = aDestRectAbs.Width();
   788 		const TInt clipLen = aClipRectAbs.Width();
   789 
   790 		// clipPos doesn't need to be inverted (using iBr.iX) because the yScaler below
   791 		// will do that for us (by stepping backward)
   792 		//
   793 		const TInt clipPos = aClipRectAbs.iTl.iX - aDestRectAbs.iTl.iX;
   794 
   795 		// setup DDA for scaling in Y direction based on src rect and dst rect size
   796 		// scaling in X direction will be done by GetScaledScanLine()
   797 		//
   798 		// setup Y scaler and start from bottom-right of src/dest to top-left of src/dest
   799 		// to do backward stepping (src Y inversion)
   800 
   801 		TLinearDDA yScaler;
   802 		yScaler.Construct(
   803 				// we starting from 1st pixel from bottom of source image, we need to
   804 				// step back 1 position as bottom-row coord is beyond the last pixel in the source rect
   805 				TPoint(aSrcRect.iBr.iY - 1, aDestRectAbs.iTl.iY),
   806 				TPoint(aSrcRect.iTl.iY - 1, aDestRectAbs.iBr.iY),
   807 				TLinearDDA::ELeft);
   808 
   809 		// move to position of current clip rect top row as the start of dest Y
   810 		// which will calculate inverted src Y distance from bottom of source rectangle
   811 		TInt invSrcY;	
   812 		yScaler.JumpToYCoord2(invSrcY, aClipRectAbs.iTl.iY);
   813 
   814 		// yPos contains mapping between inverted src Y (TPoint.iX) and dest Y (TPoint.iY)
   815 		TPoint yPos(invSrcY, aClipRectAbs.iTl.iY);
   816 
   817 		// write to target from top to bottom
   818 		//
   819 		while (yPos.iY < aClipRectAbs.iBr.iY)
   820 			{
   821 			// read scanline from righ to left i.e. use aSrcRect.iBr.iX-1 (last column)
   822 			// as starting src X value
   823 			reader.GetScaledScanLine(scanLineDes,
   824 									TPoint(aSrcRect.iBr.iX - 1, yPos.iX),	// src X and inverted src Y
   825 									clipPos,								// clipped dest X
   826 									clipLen,
   827 									destLen,
   828 									srcLen,
   829 									readFormat,
   830 									TPixelBufferReader::EReadHorizontalReverse);
   831 			
   832 			// use dest Y here
   833 			writer.WriteLine(aClipRectAbs.iTl.iX, yPos.iY, clipLen, scanLineBuffer, drawMode);
   834 
   835 			// move scaler one position
   836 			yScaler.NextStep(yPos);
   837 			}
   838 		}
   839 	else if(aRotation == DirectGdi::EGraphicsRotation270)
   840 		{
   841 		// we're going to read source vertically from top to bottom, swap relevant bits and pieces
   842 		// dst-width corresponds to src-height
   843 		// dst-height corresponds to src-width
   844 		const TInt srcLen = aSrcRect.Height();
   845 		const TInt destLen = aDestRectAbs.Width();
   846 
   847 		// the following doesn't change, the amount of pixel read (vertically) will be based on
   848 		// the drawing area witdh i.e. clip width
   849 		const TInt clipLen = aClipRectAbs.Width();
   850 
   851 		// offset into read area doesn't change either, it will be translated into some Y position
   852 		// from top row of source image
   853 		const TInt clipPos = aClipRectAbs.iTl.iX - aDestRectAbs.iTl.iX;
   854 
   855 		// setup DDA for scaling in src X direction based on src rect and dst rect size
   856 		// scaling in src Y direction will be done by GetScaledScanLine(EReadVertical)
   857 		//
   858 		// scaler map dest Y to src X because of 270 degre rotation
   859 		// start from top row dest, right-most column src to bottom row dest, left-most column src
   860 
   861 		TLinearDDA xScaler;
   862 		xScaler.Construct(
   863 				// decrement 1 pixel to get into last pixel within source
   864 				TPoint(aSrcRect.iBr.iX - 1, aDestRectAbs.iTl.iY),
   865 				TPoint(aSrcRect.iTl.iX - 1, aDestRectAbs.iBr.iY),
   866 				TLinearDDA::ELeft);
   867 
   868 		// move to position of current clip rect top row as the start of src X
   869 		TInt srcX;	
   870 		xScaler.JumpToYCoord2(srcX, aClipRectAbs.iTl.iY);
   871 		// xPos contains mapping between src X (TPoint.iX) and dest Y (TPoint.iY)
   872 		TPoint xPos(srcX, aClipRectAbs.iTl.iY);
   873 
   874 		// write to target from top to bottom
   875 		//
   876 		while (xPos.iY < aClipRectAbs.iBr.iY)
   877 			{
   878 			// read pixel vertically from left column to right
   879 			reader.GetScaledScanLine(scanLineDes,
   880 									TPoint(xPos.iX, aSrcRect.iTl.iY),		// src X, src Y
   881 									clipPos,								// distance from bottom source
   882 									clipLen,
   883 									destLen,
   884 									srcLen,
   885 									readFormat,
   886 									TPixelBufferReader::EReadVertical);
   887 			
   888 			// use dest Y here
   889 			writer.WriteLine(aClipRectAbs.iTl.iX, xPos.iY, clipLen, scanLineBuffer, drawMode);
   890 
   891 			// move scaler one position
   892 			xScaler.NextStep(xPos);
   893 			}
   894 		}
   895 	}