graphicsdeviceinterface/directgdiadaptation/swsrc/swdirectgdidrawresource.cpp
changeset 0 5d03bc08d59c
equal deleted inserted replaced
-1:000000000000 0:5d03bc08d59c
       
     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 	}