os/graphics/graphicsdeviceinterface/directgdiadaptation/swsrc/swdirectgdidrawresource.cpp
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/graphics/graphicsdeviceinterface/directgdiadaptation/swsrc/swdirectgdidrawresource.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,895 @@
1.4 +// Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +//
1.18 +
1.19 +#include "directgdiadapter.h"
1.20 +#include "swdirectgdiengine.h"
1.21 +#include "swdirectgdiimagesourceimpl.h"
1.22 +#include "swdirectgdidriverimpl.h"
1.23 +#include <bitdrawinterfaceid.h>
1.24 +#include <e32cmn.h>
1.25 +#include <bitdraw.h>
1.26 +#include <bmalphablend.h>
1.27 +#include <graphics/directgdidrawablesource.h>
1.28 +#include <pixelformats.h>
1.29 +#include "pixelutil.h"
1.30 +
1.31 +/**
1.32 +Helper class to deal with the case of blending 32-bit MAP source into 16-bit target which is not
1.33 +supported by screen driver CDrawSixteenBppBitmap implementation.
1.34 +
1.35 +@publishedPartner
1.36 +@prototype
1.37 +@deprecated
1.38 +*/
1.39 +class TDrawDeviceWrapper
1.40 + {
1.41 +public:
1.42 + TDrawDeviceWrapper(CFbsDrawDevice* aDrawDevice, CGraphicsContext::TDrawMode aDrawMode);
1.43 + inline void WriteLine(TInt aX, TInt aY, TInt aLength, TUint32* aBuffer, CGraphicsContext::TDrawMode aDrawMode);
1.44 +private:
1.45 + inline TUint16 ConvertTo64K(TUint32 aColor);
1.46 + inline TUint16 Blend16MapTo64K(TUint16 aDest, TUint32 aSrc);
1.47 + void BlendLine16MapTo64K(TInt aX, TInt aY, TInt aLength, TUint32* aBuffer, CGraphicsContext::TDrawMode aDrawMode);
1.48 + void OriginalWriteLine(TInt aX, TInt aY, TInt aLength, TUint32* aBuffer, CGraphicsContext::TDrawMode aDrawMode);
1.49 +
1.50 +private:
1.51 + CFbsDrawDevice* iDrawDevice;
1.52 + TUint32* iBits;
1.53 +
1.54 + typedef void (TDrawDeviceWrapper::*TWriteLineFunc)(TInt,TInt,TInt,TUint32*,CGraphicsContext::TDrawMode);
1.55 + TWriteLineFunc iWriteLineFunc;
1.56 + };
1.57 +
1.58 +TDrawDeviceWrapper::TDrawDeviceWrapper(CFbsDrawDevice* aDrawDevice, CGraphicsContext::TDrawMode aDrawMode):
1.59 + iDrawDevice(aDrawDevice)
1.60 + {
1.61 + TAny* interface = NULL;
1.62 + TInt err = iDrawDevice->GetInterface(KFastBlit2InterfaceID, interface);
1.63 + // interface is guaranted to exist for 16-bit and 32-bit draw device
1.64 + GRAPHICS_ASSERT_DEBUG(err == KErrNone, EDirectGdiPanicUnexpectedError);
1.65 +
1.66 + iBits = (TUint32*) reinterpret_cast<MFastBlit2*>(interface)->Bits();
1.67 +
1.68 + // setup which funtion to call here rather tha making decision inside WriteLine which is usually called within
1.69 + // a tight scanline loop
1.70 + iWriteLineFunc = iDrawDevice->DisplayMode() == EColor64K && aDrawMode == CGraphicsContext::EDrawModePEN ?
1.71 + &TDrawDeviceWrapper::BlendLine16MapTo64K : &TDrawDeviceWrapper::OriginalWriteLine;
1.72 + }
1.73 +
1.74 +inline void TDrawDeviceWrapper::WriteLine(TInt aX, TInt aY, TInt aLength, TUint32* aBuffer, CGraphicsContext::TDrawMode aDrawMode)
1.75 + {
1.76 + // calling member functions via pointer to member functions i.e.
1.77 + // (object.*member_fn)(arg)
1.78 + //
1.79 + (this->*iWriteLineFunc)(aX, aY, aLength, aBuffer, aDrawMode);
1.80 + }
1.81 +
1.82 +void TDrawDeviceWrapper::OriginalWriteLine(TInt aX, TInt aY, TInt aLength, TUint32* aBuffer, CGraphicsContext::TDrawMode aDrawMode)
1.83 + {
1.84 + iDrawDevice->WriteLine(aX, aY, aLength, aBuffer, aDrawMode);
1.85 + }
1.86 +
1.87 +void TDrawDeviceWrapper::BlendLine16MapTo64K(TInt aX, TInt aY, TInt aLength, TUint32* aBuffer, CGraphicsContext::TDrawMode)
1.88 + {
1.89 + TUint16* pixelPtr = reinterpret_cast<TUint16*>(iBits);
1.90 + pixelPtr += (aY * iDrawDevice->LongWidth()) + aX;
1.91 + const TUint32* bufferPtr = aBuffer;
1.92 + const TUint32* bufferPtrLimit = bufferPtr + aLength;
1.93 +
1.94 + while (bufferPtr < bufferPtrLimit)
1.95 + {
1.96 + *pixelPtr = Blend16MapTo64K(*pixelPtr, *bufferPtr);
1.97 + ++bufferPtr;
1.98 + ++pixelPtr;
1.99 + }
1.100 + }
1.101 +
1.102 +inline TUint16 TDrawDeviceWrapper::ConvertTo64K(TUint32 aSrc)
1.103 + {
1.104 + TInt col = (aSrc & 0x0000f8) >> 3;
1.105 + col |= (aSrc & 0x00fc00) >> 5;
1.106 + col |= (aSrc & 0xf80000) >> 8;
1.107 +
1.108 + return col;
1.109 + }
1.110 +
1.111 +inline TUint16 TDrawDeviceWrapper::Blend16MapTo64K(TUint16 aDst, TUint32 aSrc)
1.112 + {
1.113 + const TInt alpha = aSrc >> 24;
1.114 +
1.115 + if(alpha == 0x00)
1.116 + {
1.117 + return aDst;
1.118 + }
1.119 +
1.120 + if (alpha == 0xff)
1.121 + {
1.122 + return ConvertTo64K(aSrc);
1.123 + }
1.124 +
1.125 + // extract source components from 16MAP
1.126 + const TInt src_rb = aSrc & 0x00ff00ff;
1.127 + const TInt src_g = aSrc & 0x0000ff00;
1.128 + const TInt oneMinusAlpha = 0x0100 - alpha;
1.129 +
1.130 + // extract destination components from 64K format
1.131 + TInt dr = (aDst & 0xf800) >> 8;
1.132 + dr += dr >> 5;
1.133 + TInt dg = (aDst & 0x07e0) >> 3;
1.134 + dg += dg >> 6;
1.135 + TInt db = (aDst & 0x001f) << 3;
1.136 + db += db >> 5;
1.137 +
1.138 + // combine red and blue components into a word to combine mult in one go
1.139 + TInt dst_rb = (dr << 16) | db;
1.140 + TInt dst_g = dg << 8;
1.141 +
1.142 + // dst and src are in pre-multiplied format (64K can be treated both as pre or non-pre)
1.143 + // dst = src + (1-alpha) * dst
1.144 + //
1.145 + dst_rb = (src_rb + ((oneMinusAlpha * dst_rb) >> 8)) & 0x00ff00ff;
1.146 + dst_g = (src_g + ((oneMinusAlpha * dst_g) >> 8)) & 0x0000ff00;
1.147 +
1.148 + const TUint32 argb = 0xff000000 | dst_rb | dst_g;
1.149 + return ConvertTo64K(argb);
1.150 + }
1.151 +
1.152 +//
1.153 +// implements MDirectGdiEngine interfaces
1.154 +//
1.155 +
1.156 +/**
1.157 +@see MDirectGdiEngine::DrawResource(const TRect&,const RDirectGdiDrawableSource&,const TDesC8&)
1.158 +*/
1.159 +void CSwDirectGdiEngine::DrawResource(
1.160 + const TRect& aDestRect,
1.161 + const RDirectGdiDrawableSource& aSource,
1.162 + const TDesC8& /*aParam*/)
1.163 + {
1.164 + // DirectGDI reference implementation only support pixel based resource
1.165 + // see CSwDirectGdiDriverImpl::CreateDrawableSource()
1.166 + //
1.167 + CSwDirectGdiImageSourceImpl* imgSrc = NULL;
1.168 + TSize imgSize;
1.169 + if (CheckImageSource(aSource.Handle(), imgSrc, &imgSize) != KErrNone)
1.170 + {
1.171 + return;
1.172 + }
1.173 +
1.174 + // drawing resource unscaled with no rotation
1.175 + //
1.176 + DrawResourceCommon(aDestRect, imgSrc, TRect(TPoint(0,0), imgSize), DirectGdi::EGraphicsRotationNone);
1.177 + }
1.178 +
1.179 +/**
1.180 +@see MDirectGdiEngine::DrawResource(const TPoint&,const RDirectGdiDrawableSource&,DirectGdi::TGraphicsRotation)
1.181 +*/
1.182 +void CSwDirectGdiEngine::DrawResource(const TPoint& aPos,
1.183 + const RDirectGdiDrawableSource& aSource,
1.184 + DirectGdi::TGraphicsRotation aRotation)
1.185 + {
1.186 + CSwDirectGdiImageSourceImpl* imgSrc = NULL;
1.187 + TSize imgSize;
1.188 + if (CheckImageSource(aSource.Handle(), imgSrc, &imgSize) != KErrNone)
1.189 + {
1.190 + return;
1.191 + }
1.192 +
1.193 + // drawing resource unscaled
1.194 + //
1.195 + // rotation will be applied before scaling, we must create destination rectangle
1.196 + // that match the size of rotated image
1.197 +
1.198 + TRect destRect(aPos, imgSize);
1.199 + if (aRotation==DirectGdi::EGraphicsRotation90 || aRotation==DirectGdi::EGraphicsRotation270)
1.200 + {
1.201 + // keep the top left corner in the same position but swap width and height
1.202 + destRect.SetWidth(imgSize.iHeight);
1.203 + destRect.SetHeight(imgSize.iWidth);
1.204 + }
1.205 +
1.206 + DrawResourceCommon(destRect, imgSrc, TRect(TPoint(0,0), imgSize), aRotation);
1.207 + }
1.208 +
1.209 +/**
1.210 +@see MDirectGdiEngine::DrawResource(const TRect&,const RDirectGdiDrawableSource&,DirectGdi::TGraphicsRotation)
1.211 +*/
1.212 +void CSwDirectGdiEngine::DrawResource(const TRect& aDestRect,
1.213 + const RDirectGdiDrawableSource& aSource,
1.214 + DirectGdi::TGraphicsRotation aRotation)
1.215 + {
1.216 + // aDestRect is not empty when we reach here
1.217 + //
1.218 + CSwDirectGdiImageSourceImpl* imgSrc = NULL;
1.219 + TSize imgSize;
1.220 + if (CheckImageSource(aSource.Handle(), imgSrc, &imgSize) != KErrNone)
1.221 + {
1.222 + return;
1.223 + }
1.224 +
1.225 + DrawResourceCommon(aDestRect, imgSrc, TRect(TPoint(0,0), imgSize), aRotation);
1.226 + }
1.227 +
1.228 +/**
1.229 +@see MDirectGdiEngine::DrawResource(const TRect&,const RDirectGdiDrawableSource&,const TRect&,DirectGdi::TGraphicsRotation)
1.230 +*/
1.231 +void CSwDirectGdiEngine::DrawResource(
1.232 + const TRect& aDestRect,
1.233 + const RDirectGdiDrawableSource& aSource,
1.234 + const TRect& aSrcRect,
1.235 + DirectGdi::TGraphicsRotation aRotation)
1.236 + {
1.237 + // pre:
1.238 + // aDestRect and aSrcRect are not empty
1.239 + //
1.240 + CSwDirectGdiImageSourceImpl* imgSrc = NULL;
1.241 + TSize imgSize;
1.242 + if (CheckImageSource(aSource.Handle(), imgSrc, &imgSize) != KErrNone)
1.243 + {
1.244 + return;
1.245 + }
1.246 +
1.247 + // check source rectangle is fully contained within the image resource extent
1.248 + if (aSrcRect.iTl.iX < 0 ||
1.249 + aSrcRect.iTl.iY < 0 ||
1.250 + aSrcRect.iBr.iX > imgSize.iWidth ||
1.251 + aSrcRect.iBr.iY > imgSize.iHeight)
1.252 + {
1.253 + iDriver->SetError(KErrArgument);
1.254 + return;
1.255 + }
1.256 +
1.257 + DrawResourceCommon(aDestRect, imgSrc, aSrcRect, aRotation);
1.258 + }
1.259 +
1.260 +//
1.261 +// internal functions
1.262 +//
1.263 +/**
1.264 +Checks image resource is fully constructed and registered with the driver.
1.265 +
1.266 +@param aHandle A valid handle to an image source.
1.267 +@param aImg On return, contains the image source.
1.268 +@param aSize If not NULL, will contain the dimensions of the image source.
1.269 +@return KErrNone if successful, KErrBadHandle if aHandle is not a valid handle to an image source.
1.270 +*/
1.271 +TInt CSwDirectGdiEngine::CheckImageSource(TInt aHandle, CSwDirectGdiImageSourceImpl*& aImg, TSize* aSize)
1.272 + {
1.273 + // check image exist
1.274 + if (!iDriver->ValidImageSource(aHandle))
1.275 + {
1.276 + // replace KErrNotFound
1.277 + const TInt err = KErrBadHandle;
1.278 + iDriver->SetError(err);
1.279 + return err;
1.280 + }
1.281 +
1.282 + aImg = reinterpret_cast<CSwDirectGdiImageSourceImpl*>(aHandle);
1.283 +
1.284 + // RSgImage cannot be created with zero size, so there is no point in validating its size and
1.285 + // simply return image size if requested
1.286 + if (aSize)
1.287 + {
1.288 + *aSize = aImg->Size();
1.289 + }
1.290 +
1.291 + return KErrNone;
1.292 + }
1.293 +
1.294 +/**
1.295 +Implements common DrawResource() functionality used by all DrawResource() variants.
1.296 +*/
1.297 +void CSwDirectGdiEngine::DrawResourceCommon(
1.298 + const TRect& aDestRect,
1.299 + const CSwDirectGdiImageSourceImpl* aImg,
1.300 + const TRect& aSrcRect,
1.301 + DirectGdi::TGraphicsRotation aRotation)
1.302 + {
1.303 + // pre:
1.304 + // aDestRect and aSrcRect are not empty
1.305 + // aSrcRect is within the image extent
1.306 + //
1.307 + // translate relative coord to target absolute coord system
1.308 + TRect destRectAbs(aDestRect);
1.309 + destRectAbs.Move(iOrigin);
1.310 +
1.311 + // check whether we need to blend or write
1.312 + const TBool opaqueSource = (!PixelFormatUtil::HasAlpha(aImg->PixelFormat())) && (iDrawMode == DirectGdi::EDrawModePEN);
1.313 + if (opaqueSource)
1.314 + {
1.315 + iDrawMode = DirectGdi::EDrawModeWriteAlpha;
1.316 + }
1.317 +
1.318 + // repeat drawing op for each rectangle in the clipping region
1.319 + const TInt numOfRects = iDefaultRegionPtr->Count();
1.320 + for (TInt idx = 0; idx < numOfRects; ++idx)
1.321 + {
1.322 + TRect clipRectAbs = (*iDefaultRegionPtr)[idx];
1.323 + if (!clipRectAbs.Intersects(destRectAbs))
1.324 + {
1.325 + continue;
1.326 + }
1.327 +
1.328 + // intersect current clip rect with dest rect to get actual draw area
1.329 + clipRectAbs.Intersection(destRectAbs);
1.330 + DoDrawResource(destRectAbs, aImg, aSrcRect, aRotation, clipRectAbs);
1.331 +
1.332 + iDrawDevice->UpdateRegion(clipRectAbs);
1.333 + }
1.334 +
1.335 + if (opaqueSource)
1.336 + {
1.337 + iDrawMode = DirectGdi::EDrawModePEN;
1.338 + }
1.339 + }
1.340 +
1.341 +/**
1.342 +Rotate a given rectangle 90 degree clockwise around the specified origin.
1.343 +*/
1.344 +void CSwDirectGdiEngine::Rotate90(TRect& aRect, const TPoint& aOrigin)
1.345 + {
1.346 + // rotated bottom-left become top-left of rotated rect
1.347 + //
1.348 + TPoint bl(aRect.iTl.iX, aRect.iBr.iY);
1.349 + const TInt w = aRect.Width();
1.350 + const TInt h = aRect.Height();
1.351 +
1.352 + const TPoint dbl = bl - aOrigin;
1.353 + bl.iX = aOrigin.iX - dbl.iY;
1.354 + bl.iY = aOrigin.iY + dbl.iX;
1.355 +
1.356 + aRect = TRect(bl, TSize(h,w));
1.357 + }
1.358 +
1.359 +/**
1.360 +Rotate a given rectangle 180 degree clockwise around the specified origin.
1.361 +*/
1.362 +void CSwDirectGdiEngine::Rotate180(TRect& aRect, const TPoint& aOrigin)
1.363 + {
1.364 + // rotated bottom-right become top-left of rotated rect
1.365 + //
1.366 + TPoint br(aRect.iBr);
1.367 + const TSize sz = aRect.Size();
1.368 +
1.369 + const TPoint dbr = br - aOrigin;
1.370 + br.iX = aOrigin.iX - dbr.iX;
1.371 + br.iY = aOrigin.iY - dbr.iY;
1.372 +
1.373 + aRect = TRect(br, sz);
1.374 + }
1.375 +
1.376 +/**
1.377 +Rotate a given rectangle 270 degree clockwise around the specified origin.
1.378 +*/
1.379 +void CSwDirectGdiEngine::Rotate270(TRect& aRect, const TPoint& aOrigin)
1.380 + {
1.381 + // rotated top-right become top-left of rotated rect
1.382 + //
1.383 + TPoint tr(aRect.iBr.iX, aRect.iTl.iY);
1.384 + const TInt w = aRect.Width();
1.385 + const TInt h = aRect.Height();
1.386 +
1.387 + const TPoint dtr = tr - aOrigin;
1.388 + tr.iX = aOrigin.iX + dtr.iY;
1.389 + tr.iY = aOrigin.iY - dtr.iX;
1.390 +
1.391 + aRect = TRect(tr, TSize(h,w));
1.392 + }
1.393 +
1.394 +/**
1.395 +Tests that the size of a given rotated rectangle match the image source extent.
1.396 +*/
1.397 +TBool CSwDirectGdiEngine::RotatedSizeMatch(const TRect& aDst, const TRect& aSrc, DirectGdi::TGraphicsRotation aRot)
1.398 + {
1.399 + if (aRot==DirectGdi::EGraphicsRotationNone || aRot==DirectGdi::EGraphicsRotation180)
1.400 + {
1.401 + return aDst.Size()==aSrc.Size();
1.402 + }
1.403 + else
1.404 + {
1.405 + return aDst.Width()==aSrc.Height() && aDst.Height()==aSrc.Width();
1.406 + }
1.407 + }
1.408 +
1.409 +/**
1.410 +Draws a rectangular area of resource and apply rotation and/or scaling if requested.
1.411 +*/
1.412 +void CSwDirectGdiEngine::DoDrawResource(
1.413 + const TRect& aDestRectAbs,
1.414 + const CSwDirectGdiImageSourceImpl* aImg,
1.415 + const TRect& aSrcRect,
1.416 + DirectGdi::TGraphicsRotation aRotation,
1.417 + const TRect& aClipRectAbs)
1.418 + {
1.419 + // pre:
1.420 + // SetClippingRegion() already check that clipping region is always contained
1.421 + // within device full extent.
1.422 +
1.423 + // check src rect match the size of rotated dest rect
1.424 + if (RotatedSizeMatch(aDestRectAbs, aSrcRect, aRotation))
1.425 + {
1.426 + // aClipRect is the effective drawing clipped area, it has been intersected with dest rect by the
1.427 + // calling function/DoDrawResourceCommon() and it is not empty when we reach here
1.428 +
1.429 + // image size has been checked at the top level DrawResource() no need to check it again
1.430 +
1.431 + // use aClipRect to determine how much area should be read from the image and transform
1.432 + // the effective read area into source rect depending on rotation parameter
1.433 +
1.434 + // start with aClipRect
1.435 + TRect xformSrcRect(aClipRectAbs);
1.436 + switch (aRotation)
1.437 + {
1.438 + case DirectGdi::EGraphicsRotationNone:
1.439 + // align top-left corner of dest rect with top-left corner of src rect
1.440 + xformSrcRect.Move(aSrcRect.iTl - aDestRectAbs.iTl);
1.441 + break;
1.442 + case DirectGdi::EGraphicsRotation90:
1.443 + {
1.444 + // align top-right corner of dest rect with top-left corner of src rect
1.445 + xformSrcRect.Move(aSrcRect.iTl - TPoint(aDestRectAbs.iBr.iX, aDestRectAbs.iTl.iY));
1.446 + // rotate 270 (-90) degree using top-left corner of src rect as pivot point
1.447 + Rotate270(xformSrcRect, aSrcRect.iTl);
1.448 + }
1.449 + break;
1.450 + case DirectGdi::EGraphicsRotation180:
1.451 + {
1.452 + // align bottom-right corner of dest rect with top-left corner of src rect
1.453 + xformSrcRect.Move(aSrcRect.iTl - aDestRectAbs.iBr);
1.454 + // rotate 180 (-180) degree using top-left corner of src rect as pivot point
1.455 + Rotate180(xformSrcRect, aSrcRect.iTl);
1.456 + }
1.457 + break;
1.458 + case DirectGdi::EGraphicsRotation270:
1.459 + {
1.460 + // align bottom-left corner of dest rect with top-left corner of src rect
1.461 + xformSrcRect.Move(aSrcRect.iTl - TPoint(aDestRectAbs.iTl.iX, aDestRectAbs.iBr.iY));
1.462 + // rotate 90 (-270) degree using top-left corner of src rect as pivot point
1.463 + Rotate90(xformSrcRect, aSrcRect.iTl);
1.464 + }
1.465 + break;
1.466 +
1.467 + // no need for extra check, aRotation has been checked at generic layer
1.468 + }
1.469 +
1.470 + DoBlitResource(aClipRectAbs.iTl, aImg, xformSrcRect, aRotation);
1.471 + return;
1.472 + }
1.473 +
1.474 + DoScaledBlitResource(aDestRectAbs, aImg, aSrcRect, aRotation, aClipRectAbs);
1.475 + }
1.476 +
1.477 +/**
1.478 +Draws a rectangular area of resource rotated with no scaling.
1.479 +@panic DGDIAdapter 1009, if the pixel format of the draw device is unknown (debug only).
1.480 +*/
1.481 +void CSwDirectGdiEngine::DoBlitResource(
1.482 + const TPoint& aDest,
1.483 + const CSwDirectGdiImageSourceImpl* aImg,
1.484 + const TRect& aSrcRect,
1.485 + DirectGdi::TGraphicsRotation aRotation)
1.486 + {
1.487 + // pre:
1.488 + // aDest is the top-left of clipped destination rectangle i.e. intersection of user destination
1.489 + // rectangle with current clipping rect
1.490 + // aSrcRect is rotated clipped read area i.e. effective read area with respect to original
1.491 + // image orientation i.e.it no longer represents user specified source rect.
1.492 +
1.493 + // no need to do extra check on parameters here because:
1.494 + // aDest is guaranteed to be within device drawing area
1.495 + // aSrcRect is guaranteed to be within image source area
1.496 +
1.497 + const TUidPixelFormat devFormat = PixelFormatUtil::ConvertToPixelFormat(iDrawDevice->DisplayMode());
1.498 + GRAPHICS_ASSERT_DEBUG(devFormat != EUidPixelFormatUnknown, EDirectGdiPanicInvalidDisplayMode);
1.499 +
1.500 + const TUidPixelFormat imgFormat = aImg->PixelFormat();
1.501 + const TUint32* imgAddr = reinterpret_cast<TUint32*>(aImg->DataBuffer());
1.502 + const TInt imgStride = aImg->Stride();
1.503 + const TSize imgSize = aImg->Size();
1.504 + const CGraphicsContext::TDrawMode drawMode = GcDrawMode(iDrawMode);
1.505 +
1.506 + const TInt width = aSrcRect.Width();
1.507 + const TInt height = aSrcRect.Height();
1.508 + // write scanline starting from top dest row
1.509 + TInt destY = aDest.iY;
1.510 + // setup pixel reader toolkit
1.511 + TPixelBufferReader reader(imgAddr, imgSize, imgStride, imgFormat);
1.512 + TDrawDeviceWrapper writer(iDrawDevice, GcDrawMode(iDrawMode));
1.513 +
1.514 + //
1.515 + // special case when rotation is none
1.516 + //
1.517 + if (aRotation == DirectGdi::EGraphicsRotationNone)
1.518 + {
1.519 + TAny* interface = NULL;
1.520 +
1.521 + // source and destination format match and using write alpha mode i.e. reduce blit to memcpy
1.522 + if (iDrawMode == DirectGdi::EDrawModeWriteAlpha && devFormat == imgFormat)
1.523 + {
1.524 + TInt err = iDrawDevice->GetInterface(KFastBlit2InterfaceID, interface);
1.525 + if (err == KErrNone)
1.526 + {
1.527 + GRAPHICS_ASSERT_DEBUG(interface, EDirectGdiPanicInvalidPointer);
1.528 + MFastBlit2* fblit = static_cast<MFastBlit2*>(interface);
1.529 + err = fblit->WriteBitmapBlock(aDest, imgAddr, imgStride, imgSize, aSrcRect);
1.530 + if (err == KErrNone)
1.531 + {
1.532 + return;
1.533 + }
1.534 + }
1.535 + }
1.536 +
1.537 + // fallback from MFastBlit2 when source and destination format match.
1.538 + // Note that there was previously an optimization added here that used MFlastBlend if
1.539 + // available, however it did not work correctly for some cases using DrawResource so has been
1.540 + // removed from this code. (A source drawn with OpenGLES on to a target in XRGB_8888 format
1.541 + // actually had alpha in the unused channel which was being drawn by MFastBlend)
1.542 + if (devFormat == imgFormat)
1.543 + {
1.544 + for (TInt row=aSrcRect.iTl.iY; row<aSrcRect.iBr.iY; ++row,++destY)
1.545 + {
1.546 + const TPoint pos(aSrcRect.iTl.iX, row);
1.547 + const TUint32* slptr = reader.GetPixelAddr(pos);
1.548 + writer.WriteLine(aDest.iX, destY, width, const_cast<TUint32*>(slptr), drawMode);
1.549 + }
1.550 +
1.551 + return;
1.552 + }
1.553 +
1.554 + // there is one additional case that can be optimised by eleminating copy when:
1.555 + // rotation : none
1.556 + // scaling : none
1.557 + // dst : opaque
1.558 + // src : has alpha and premultiplied
1.559 + // mode : PEN
1.560 + }
1.561 +
1.562 + //
1.563 + // generic cases
1.564 + //
1.565 + // copying is necessary either to convert pixel format or to read back buffer in reverse order
1.566 + // to achieve rotation
1.567 + //
1.568 + const TInt scanLineBytes = iDrawDevice->ScanLineBytes();
1.569 + TUint32* scanLineBuffer = iDrawDevice->ScanLineBuffer();
1.570 + TPtr8 scanLineDes(reinterpret_cast<TUint8*>(scanLineBuffer),scanLineBytes,scanLineBytes);
1.571 +
1.572 + // if destination is opaque e.g. RGB_565, XRGB_8888 and the source has alpha, it shall blend
1.573 + // (because iDrawMode is set to WritePEN)
1.574 + // we treat opaque destination as in pre-multiplied format (with alpha value 1), and read the
1.575 + // source in pre-multiplied format too, to enable optimum blending computation i.e.
1.576 + // "src + (1-alpha) * dst"
1.577 + const TUidPixelFormat readFormat = !PixelFormatUtil::HasAlpha(devFormat) &&
1.578 + iDrawMode == DirectGdi::EDrawModePEN ?
1.579 + EUidPixelFormatARGB_8888_PRE : devFormat;
1.580 +
1.581 + if (aRotation == DirectGdi::EGraphicsRotationNone)
1.582 + {
1.583 + // general fallback from FastBlendBitmap
1.584 + //
1.585 + const TInt readLen = width;
1.586 + // normal read scanline, left to right
1.587 + //
1.588 + for (TInt row=aSrcRect.iTl.iY; row<aSrcRect.iBr.iY; ++row,++destY)
1.589 + {
1.590 + const TPoint pos(aSrcRect.iTl.iX, row);
1.591 + reader.GetScanLine(scanLineDes,pos, readLen, readFormat, TPixelBufferReader::EReadHorizontal);
1.592 + writer.WriteLine(aDest.iX, destY, readLen, scanLineBuffer, drawMode);
1.593 + }
1.594 + }
1.595 + else if (aRotation == DirectGdi::EGraphicsRotation90)
1.596 + {
1.597 + const TInt readLen = height;
1.598 + // read scanline vertically from bottom to up, and from the lef-most column
1.599 + //
1.600 + for (TInt col=aSrcRect.iTl.iX; col<aSrcRect.iBr.iX; ++col,++destY)
1.601 + {
1.602 + const TPoint pos(col, aSrcRect.iBr.iY-1);
1.603 + reader.GetScanLine(scanLineDes, pos, readLen, readFormat, TPixelBufferReader::EReadVerticalReverse);
1.604 + writer.WriteLine(aDest.iX, destY, readLen, scanLineBuffer, drawMode);
1.605 + }
1.606 + }
1.607 + else if (aRotation == DirectGdi::EGraphicsRotation180)
1.608 + {
1.609 + const TInt readLen = width;
1.610 + // read scanline from right to left, starting from the most bottom scanline
1.611 + //
1.612 + for (TInt row=aSrcRect.iBr.iY-1; row>=aSrcRect.iTl.iY; --row,++destY)
1.613 + {
1.614 + const TPoint pos(aSrcRect.iBr.iX-1, row);
1.615 + reader.GetScanLine(scanLineDes, pos, readLen, readFormat, TPixelBufferReader::EReadHorizontalReverse);
1.616 + writer.WriteLine(aDest.iX, destY, readLen, scanLineBuffer, drawMode);
1.617 + }
1.618 + }
1.619 + else if (aRotation == DirectGdi::EGraphicsRotation270)
1.620 + {
1.621 + const TInt readLen = height;
1.622 + // read scanline vertically top to bottom, and from the right-most column
1.623 + //
1.624 + for (TInt col=aSrcRect.iBr.iX-1; col>=aSrcRect.iTl.iX; --col,++destY)
1.625 + {
1.626 + const TPoint pos(col, aSrcRect.iTl.iY);
1.627 + reader.GetScanLine(scanLineDes, pos, readLen, readFormat, TPixelBufferReader::EReadVertical);
1.628 + writer.WriteLine(aDest.iX, destY, readLen, scanLineBuffer, drawMode);
1.629 + }
1.630 + }
1.631 + }
1.632 +
1.633 +/**
1.634 +Draws a rectangular area of resource rotated and/or scaled up/down.
1.635 +@panic DGDIAdapter 1009, if the pixel format of the draw device is unknown (debug only).
1.636 +*/
1.637 +void CSwDirectGdiEngine::DoScaledBlitResource(
1.638 + const TRect& aDestRectAbs,
1.639 + const CSwDirectGdiImageSourceImpl* aImg,
1.640 + const TRect& aSrcRect,
1.641 + DirectGdi::TGraphicsRotation aRotation,
1.642 + const TRect& aClipRectAbs)
1.643 + {
1.644 + // pre:
1.645 + // aDestRectAbs is the user specified dest rect that has been translated to target coord system. It may
1.646 + // be larger/outside the target drawing area. We must not modify this rect as it will be used to
1.647 + // determine the scaling factor.
1.648 + // aSrcRect is the user specified src rect, it is within the image extent.
1.649 + // aClipRectAbs is the intersection of current clipping rect and aDestRectAbs and is within the
1.650 + // target drawing area.
1.651 +
1.652 + const TUidPixelFormat devFormat = PixelFormatUtil::ConvertToPixelFormat(iDrawDevice->DisplayMode());
1.653 + GRAPHICS_ASSERT_DEBUG(devFormat != EUidPixelFormatUnknown, EDirectGdiPanicInvalidDisplayMode);
1.654 +
1.655 + const TUint32* imgAddr = reinterpret_cast<TUint32*>(aImg->DataBuffer());
1.656 + const TInt imgStride = aImg->Stride();
1.657 + const TSize imgSize = aImg->Size();
1.658 + const TUidPixelFormat imgFormat = aImg->PixelFormat();
1.659 + const CGraphicsContext::TDrawMode drawMode = GcDrawMode(iDrawMode);
1.660 +
1.661 + // if destination is opaque e.g. RGB_565, XRGB_8888 and the source has alpha, it shall blend
1.662 + // (because iDrawMode is set to WritePEN)
1.663 + // we treat opaque destination as in pre-multiplied format (with alpha value 1), and read the
1.664 + // source in pre-multiplied format too, to enable optimum blending computation i.e.
1.665 + // "src + (1-alpha) * dst"
1.666 + const TUidPixelFormat readFormat = !PixelFormatUtil::HasAlpha(devFormat) &&
1.667 + iDrawMode == DirectGdi::EDrawModePEN ?
1.668 + EUidPixelFormatARGB_8888_PRE : devFormat;
1.669 +
1.670 + TUint32* scanLineBuffer = iDrawDevice->ScanLineBuffer();
1.671 + const TInt scanLineBytes = iDrawDevice->ScanLineBytes();
1.672 + TPtr8 scanLineDes(reinterpret_cast<TUint8*>(scanLineBuffer), scanLineBytes, scanLineBytes);
1.673 +
1.674 + // setup pixel reader toolkit
1.675 + //
1.676 + TPixelBufferReader reader(imgAddr, imgSize, imgStride, imgFormat);
1.677 + TDrawDeviceWrapper writer(iDrawDevice, GcDrawMode(iDrawMode));
1.678 +
1.679 + if (aRotation == DirectGdi::EGraphicsRotationNone)
1.680 + {
1.681 + // Note that there was previously an optimization added here that used MFlastBlend if
1.682 + // available, however it did not work correctly for some cases using DrawResource so has been
1.683 + // removed from this code. (A source drawn with OpenGLES on to a target in XRGB_8888 format
1.684 + // actually had alpha in the unused channel which was being drawn by MFastBlend)
1.685 + //
1.686 + const TInt srcLen = aSrcRect.Width();
1.687 + const TInt destLen = aDestRectAbs.Width();
1.688 + const TInt clipLen = aClipRectAbs.Width();
1.689 + const TInt clipPos = aClipRectAbs.iTl.iX - aDestRectAbs.iTl.iX;
1.690 +
1.691 + // setup DDA for scaling in Y direction based on src rect and dst rect size
1.692 + // scaling in X direction will be done by GetScaledScanLine()
1.693 + //
1.694 + // setup Y scaler and start from top-left of src/dest to bottom-right of src/dest
1.695 +
1.696 + TLinearDDA yScaler;
1.697 + yScaler.Construct(
1.698 + TPoint(aSrcRect.iTl.iY, aDestRectAbs.iTl.iY),
1.699 + TPoint(aSrcRect.iBr.iY, aDestRectAbs.iBr.iY),
1.700 + TLinearDDA::ELeft);
1.701 +
1.702 + // move to position of current clip rect top row as the start of dest Y
1.703 + TInt srcY;
1.704 + yScaler.JumpToYCoord2(srcY, aClipRectAbs.iTl.iY);
1.705 +
1.706 + // yPos contains mapping between src Y (TPoint.iX) and dest Y (TPoint.iY)
1.707 + TPoint yPos(srcY, aClipRectAbs.iTl.iY);
1.708 +
1.709 + // write to target from top to bottom
1.710 + //
1.711 + while (yPos.iY < aClipRectAbs.iBr.iY)
1.712 + {
1.713 + reader.GetScaledScanLine(scanLineDes,
1.714 + TPoint(aSrcRect.iTl.iX, yPos.iX), // src X and Y
1.715 + clipPos, // clipped dest X
1.716 + clipLen,
1.717 + destLen,
1.718 + srcLen,
1.719 + readFormat,
1.720 + TPixelBufferReader::EReadHorizontal);
1.721 +
1.722 + // use dest Y here
1.723 + writer.WriteLine(aClipRectAbs.iTl.iX, yPos.iY, clipLen, scanLineBuffer, drawMode);
1.724 +
1.725 + // move scaler one position
1.726 + yScaler.NextStep(yPos);
1.727 + };
1.728 + }
1.729 + else if (aRotation == DirectGdi::EGraphicsRotation90)
1.730 + {
1.731 + // we're going to read source vertically from bottom to up, swap relevant bits and pieces
1.732 + // dst-width corresponds to src-height
1.733 + // dst-height corresponds to src-width
1.734 + //
1.735 + const TInt srcLen = aSrcRect.Height();
1.736 + const TInt destLen = aDestRectAbs.Width();
1.737 +
1.738 + // the following doesn't change, the amount of pixel read (vertically) will be based on
1.739 + // the drawing area witdh i.e. clip width
1.740 + //
1.741 + const TInt clipLen = aClipRectAbs.Width();
1.742 +
1.743 + // offset into read area doesn't change either, it will be translated into some Y position
1.744 + // from bottom row of source image
1.745 + const TInt clipPos = aClipRectAbs.iTl.iX - aDestRectAbs.iTl.iX;
1.746 +
1.747 + // setup DDA for scaling in src X direction based on src rect and dst rect size
1.748 + // scaling in src Y direction will be done by GetScaledScanLine(EReadVerticalReverse)
1.749 + //
1.750 + // scaler map dest Y to src X because of 90 degre rotation
1.751 + // start from top row dest, left-most column src to bottom row dest, right-most column src
1.752 + //
1.753 + TLinearDDA xScaler;
1.754 + xScaler.Construct(
1.755 + TPoint(aSrcRect.iTl.iX, aDestRectAbs.iTl.iY),
1.756 + TPoint(aSrcRect.iBr.iX, aDestRectAbs.iBr.iY),
1.757 + TLinearDDA::ELeft);
1.758 +
1.759 + // move to position of current clip rect top row as the start of src X
1.760 + TInt srcX;
1.761 + xScaler.JumpToYCoord2(srcX, aClipRectAbs.iTl.iY);
1.762 +
1.763 + // xPos contains mapping between src X (TPoint.iX) and dest Y (TPoint.iY)
1.764 + TPoint xPos(srcX, aClipRectAbs.iTl.iY);
1.765 +
1.766 + // write to target from top to bottom
1.767 + //
1.768 + while (xPos.iY < aClipRectAbs.iBr.iY)
1.769 + {
1.770 + // read pixel vertically from left column to right
1.771 + reader.GetScaledScanLine(scanLineDes,
1.772 + TPoint(xPos.iX, aSrcRect.iBr.iY - 1), // src X, src Y
1.773 + clipPos, // distance from bottom source
1.774 + clipLen,
1.775 + destLen,
1.776 + srcLen,
1.777 + readFormat,
1.778 + TPixelBufferReader::EReadVerticalReverse);
1.779 +
1.780 + // use dest Y here
1.781 + writer.WriteLine(aClipRectAbs.iTl.iX, xPos.iY, clipLen, scanLineBuffer, drawMode);
1.782 +
1.783 + // move scaler one position
1.784 + xScaler.NextStep(xPos);
1.785 + }
1.786 + }
1.787 + else if (aRotation == DirectGdi::EGraphicsRotation180)
1.788 + {
1.789 + const TInt srcLen = aSrcRect.Width();
1.790 + const TInt destLen = aDestRectAbs.Width();
1.791 + const TInt clipLen = aClipRectAbs.Width();
1.792 +
1.793 + // clipPos doesn't need to be inverted (using iBr.iX) because the yScaler below
1.794 + // will do that for us (by stepping backward)
1.795 + //
1.796 + const TInt clipPos = aClipRectAbs.iTl.iX - aDestRectAbs.iTl.iX;
1.797 +
1.798 + // setup DDA for scaling in Y direction based on src rect and dst rect size
1.799 + // scaling in X direction will be done by GetScaledScanLine()
1.800 + //
1.801 + // setup Y scaler and start from bottom-right of src/dest to top-left of src/dest
1.802 + // to do backward stepping (src Y inversion)
1.803 +
1.804 + TLinearDDA yScaler;
1.805 + yScaler.Construct(
1.806 + // we starting from 1st pixel from bottom of source image, we need to
1.807 + // step back 1 position as bottom-row coord is beyond the last pixel in the source rect
1.808 + TPoint(aSrcRect.iBr.iY - 1, aDestRectAbs.iTl.iY),
1.809 + TPoint(aSrcRect.iTl.iY - 1, aDestRectAbs.iBr.iY),
1.810 + TLinearDDA::ELeft);
1.811 +
1.812 + // move to position of current clip rect top row as the start of dest Y
1.813 + // which will calculate inverted src Y distance from bottom of source rectangle
1.814 + TInt invSrcY;
1.815 + yScaler.JumpToYCoord2(invSrcY, aClipRectAbs.iTl.iY);
1.816 +
1.817 + // yPos contains mapping between inverted src Y (TPoint.iX) and dest Y (TPoint.iY)
1.818 + TPoint yPos(invSrcY, aClipRectAbs.iTl.iY);
1.819 +
1.820 + // write to target from top to bottom
1.821 + //
1.822 + while (yPos.iY < aClipRectAbs.iBr.iY)
1.823 + {
1.824 + // read scanline from righ to left i.e. use aSrcRect.iBr.iX-1 (last column)
1.825 + // as starting src X value
1.826 + reader.GetScaledScanLine(scanLineDes,
1.827 + TPoint(aSrcRect.iBr.iX - 1, yPos.iX), // src X and inverted src Y
1.828 + clipPos, // clipped dest X
1.829 + clipLen,
1.830 + destLen,
1.831 + srcLen,
1.832 + readFormat,
1.833 + TPixelBufferReader::EReadHorizontalReverse);
1.834 +
1.835 + // use dest Y here
1.836 + writer.WriteLine(aClipRectAbs.iTl.iX, yPos.iY, clipLen, scanLineBuffer, drawMode);
1.837 +
1.838 + // move scaler one position
1.839 + yScaler.NextStep(yPos);
1.840 + }
1.841 + }
1.842 + else if(aRotation == DirectGdi::EGraphicsRotation270)
1.843 + {
1.844 + // we're going to read source vertically from top to bottom, swap relevant bits and pieces
1.845 + // dst-width corresponds to src-height
1.846 + // dst-height corresponds to src-width
1.847 + const TInt srcLen = aSrcRect.Height();
1.848 + const TInt destLen = aDestRectAbs.Width();
1.849 +
1.850 + // the following doesn't change, the amount of pixel read (vertically) will be based on
1.851 + // the drawing area witdh i.e. clip width
1.852 + const TInt clipLen = aClipRectAbs.Width();
1.853 +
1.854 + // offset into read area doesn't change either, it will be translated into some Y position
1.855 + // from top row of source image
1.856 + const TInt clipPos = aClipRectAbs.iTl.iX - aDestRectAbs.iTl.iX;
1.857 +
1.858 + // setup DDA for scaling in src X direction based on src rect and dst rect size
1.859 + // scaling in src Y direction will be done by GetScaledScanLine(EReadVertical)
1.860 + //
1.861 + // scaler map dest Y to src X because of 270 degre rotation
1.862 + // start from top row dest, right-most column src to bottom row dest, left-most column src
1.863 +
1.864 + TLinearDDA xScaler;
1.865 + xScaler.Construct(
1.866 + // decrement 1 pixel to get into last pixel within source
1.867 + TPoint(aSrcRect.iBr.iX - 1, aDestRectAbs.iTl.iY),
1.868 + TPoint(aSrcRect.iTl.iX - 1, aDestRectAbs.iBr.iY),
1.869 + TLinearDDA::ELeft);
1.870 +
1.871 + // move to position of current clip rect top row as the start of src X
1.872 + TInt srcX;
1.873 + xScaler.JumpToYCoord2(srcX, aClipRectAbs.iTl.iY);
1.874 + // xPos contains mapping between src X (TPoint.iX) and dest Y (TPoint.iY)
1.875 + TPoint xPos(srcX, aClipRectAbs.iTl.iY);
1.876 +
1.877 + // write to target from top to bottom
1.878 + //
1.879 + while (xPos.iY < aClipRectAbs.iBr.iY)
1.880 + {
1.881 + // read pixel vertically from left column to right
1.882 + reader.GetScaledScanLine(scanLineDes,
1.883 + TPoint(xPos.iX, aSrcRect.iTl.iY), // src X, src Y
1.884 + clipPos, // distance from bottom source
1.885 + clipLen,
1.886 + destLen,
1.887 + srcLen,
1.888 + readFormat,
1.889 + TPixelBufferReader::EReadVertical);
1.890 +
1.891 + // use dest Y here
1.892 + writer.WriteLine(aClipRectAbs.iTl.iX, xPos.iY, clipLen, scanLineBuffer, drawMode);
1.893 +
1.894 + // move scaler one position
1.895 + xScaler.NextStep(xPos);
1.896 + }
1.897 + }
1.898 + }