author | Gareth Stockwell <gareth.stockwell@accenture.com> |
Fri, 22 Oct 2010 11:38:29 +0100 | |
branch | bug235_bringup_0 |
changeset 206 | c170e304623f |
parent 0 | 5d03bc08d59c |
permissions | -rw-r--r-- |
// Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). // All rights reserved. // This component and the accompanying materials are made available // under the terms of "Eclipse Public License v1.0" // which accompanies this distribution, and is available // at the URL "http://www.eclipse.org/legal/epl-v10.html". // // Initial Contributors: // Nokia Corporation - initial contribution. // // Contributors: // // Description: // #include "directgdiadapter.h" #include "swdirectgdiengine.h" #include "swdirectgdiimagesourceimpl.h" #include "swdirectgdidriverimpl.h" #include <bitdrawinterfaceid.h> #include <e32cmn.h> #include <bitdraw.h> #include <bmalphablend.h> #include <graphics/directgdidrawablesource.h> #include <pixelformats.h> #include "pixelutil.h" /** Helper class to deal with the case of blending 32-bit MAP source into 16-bit target which is not supported by screen driver CDrawSixteenBppBitmap implementation. @publishedPartner @prototype @deprecated */ class TDrawDeviceWrapper { public: TDrawDeviceWrapper(CFbsDrawDevice* aDrawDevice, CGraphicsContext::TDrawMode aDrawMode); inline void WriteLine(TInt aX, TInt aY, TInt aLength, TUint32* aBuffer, CGraphicsContext::TDrawMode aDrawMode); private: inline TUint16 ConvertTo64K(TUint32 aColor); inline TUint16 Blend16MapTo64K(TUint16 aDest, TUint32 aSrc); void BlendLine16MapTo64K(TInt aX, TInt aY, TInt aLength, TUint32* aBuffer, CGraphicsContext::TDrawMode aDrawMode); void OriginalWriteLine(TInt aX, TInt aY, TInt aLength, TUint32* aBuffer, CGraphicsContext::TDrawMode aDrawMode); private: CFbsDrawDevice* iDrawDevice; TUint32* iBits; typedef void (TDrawDeviceWrapper::*TWriteLineFunc)(TInt,TInt,TInt,TUint32*,CGraphicsContext::TDrawMode); TWriteLineFunc iWriteLineFunc; }; TDrawDeviceWrapper::TDrawDeviceWrapper(CFbsDrawDevice* aDrawDevice, CGraphicsContext::TDrawMode aDrawMode): iDrawDevice(aDrawDevice) { TAny* interface = NULL; TInt err = iDrawDevice->GetInterface(KFastBlit2InterfaceID, interface); // interface is guaranted to exist for 16-bit and 32-bit draw device GRAPHICS_ASSERT_DEBUG(err == KErrNone, EDirectGdiPanicUnexpectedError); iBits = (TUint32*) reinterpret_cast<MFastBlit2*>(interface)->Bits(); // setup which funtion to call here rather tha making decision inside WriteLine which is usually called within // a tight scanline loop iWriteLineFunc = iDrawDevice->DisplayMode() == EColor64K && aDrawMode == CGraphicsContext::EDrawModePEN ? &TDrawDeviceWrapper::BlendLine16MapTo64K : &TDrawDeviceWrapper::OriginalWriteLine; } inline void TDrawDeviceWrapper::WriteLine(TInt aX, TInt aY, TInt aLength, TUint32* aBuffer, CGraphicsContext::TDrawMode aDrawMode) { // calling member functions via pointer to member functions i.e. // (object.*member_fn)(arg) // (this->*iWriteLineFunc)(aX, aY, aLength, aBuffer, aDrawMode); } void TDrawDeviceWrapper::OriginalWriteLine(TInt aX, TInt aY, TInt aLength, TUint32* aBuffer, CGraphicsContext::TDrawMode aDrawMode) { iDrawDevice->WriteLine(aX, aY, aLength, aBuffer, aDrawMode); } void TDrawDeviceWrapper::BlendLine16MapTo64K(TInt aX, TInt aY, TInt aLength, TUint32* aBuffer, CGraphicsContext::TDrawMode) { TUint16* pixelPtr = reinterpret_cast<TUint16*>(iBits); pixelPtr += (aY * iDrawDevice->LongWidth()) + aX; const TUint32* bufferPtr = aBuffer; const TUint32* bufferPtrLimit = bufferPtr + aLength; while (bufferPtr < bufferPtrLimit) { *pixelPtr = Blend16MapTo64K(*pixelPtr, *bufferPtr); ++bufferPtr; ++pixelPtr; } } inline TUint16 TDrawDeviceWrapper::ConvertTo64K(TUint32 aSrc) { TInt col = (aSrc & 0x0000f8) >> 3; col |= (aSrc & 0x00fc00) >> 5; col |= (aSrc & 0xf80000) >> 8; return col; } inline TUint16 TDrawDeviceWrapper::Blend16MapTo64K(TUint16 aDst, TUint32 aSrc) { const TInt alpha = aSrc >> 24; if(alpha == 0x00) { return aDst; } if (alpha == 0xff) { return ConvertTo64K(aSrc); } // extract source components from 16MAP const TInt src_rb = aSrc & 0x00ff00ff; const TInt src_g = aSrc & 0x0000ff00; const TInt oneMinusAlpha = 0x0100 - alpha; // extract destination components from 64K format TInt dr = (aDst & 0xf800) >> 8; dr += dr >> 5; TInt dg = (aDst & 0x07e0) >> 3; dg += dg >> 6; TInt db = (aDst & 0x001f) << 3; db += db >> 5; // combine red and blue components into a word to combine mult in one go TInt dst_rb = (dr << 16) | db; TInt dst_g = dg << 8; // dst and src are in pre-multiplied format (64K can be treated both as pre or non-pre) // dst = src + (1-alpha) * dst // dst_rb = (src_rb + ((oneMinusAlpha * dst_rb) >> 8)) & 0x00ff00ff; dst_g = (src_g + ((oneMinusAlpha * dst_g) >> 8)) & 0x0000ff00; const TUint32 argb = 0xff000000 | dst_rb | dst_g; return ConvertTo64K(argb); } // // implements MDirectGdiEngine interfaces // /** @see MDirectGdiEngine::DrawResource(const TRect&,const RDirectGdiDrawableSource&,const TDesC8&) */ void CSwDirectGdiEngine::DrawResource( const TRect& aDestRect, const RDirectGdiDrawableSource& aSource, const TDesC8& /*aParam*/) { // DirectGDI reference implementation only support pixel based resource // see CSwDirectGdiDriverImpl::CreateDrawableSource() // CSwDirectGdiImageSourceImpl* imgSrc = NULL; TSize imgSize; if (CheckImageSource(aSource.Handle(), imgSrc, &imgSize) != KErrNone) { return; } // drawing resource unscaled with no rotation // DrawResourceCommon(aDestRect, imgSrc, TRect(TPoint(0,0), imgSize), DirectGdi::EGraphicsRotationNone); } /** @see MDirectGdiEngine::DrawResource(const TPoint&,const RDirectGdiDrawableSource&,DirectGdi::TGraphicsRotation) */ void CSwDirectGdiEngine::DrawResource(const TPoint& aPos, const RDirectGdiDrawableSource& aSource, DirectGdi::TGraphicsRotation aRotation) { CSwDirectGdiImageSourceImpl* imgSrc = NULL; TSize imgSize; if (CheckImageSource(aSource.Handle(), imgSrc, &imgSize) != KErrNone) { return; } // drawing resource unscaled // // rotation will be applied before scaling, we must create destination rectangle // that match the size of rotated image TRect destRect(aPos, imgSize); if (aRotation==DirectGdi::EGraphicsRotation90 || aRotation==DirectGdi::EGraphicsRotation270) { // keep the top left corner in the same position but swap width and height destRect.SetWidth(imgSize.iHeight); destRect.SetHeight(imgSize.iWidth); } DrawResourceCommon(destRect, imgSrc, TRect(TPoint(0,0), imgSize), aRotation); } /** @see MDirectGdiEngine::DrawResource(const TRect&,const RDirectGdiDrawableSource&,DirectGdi::TGraphicsRotation) */ void CSwDirectGdiEngine::DrawResource(const TRect& aDestRect, const RDirectGdiDrawableSource& aSource, DirectGdi::TGraphicsRotation aRotation) { // aDestRect is not empty when we reach here // CSwDirectGdiImageSourceImpl* imgSrc = NULL; TSize imgSize; if (CheckImageSource(aSource.Handle(), imgSrc, &imgSize) != KErrNone) { return; } DrawResourceCommon(aDestRect, imgSrc, TRect(TPoint(0,0), imgSize), aRotation); } /** @see MDirectGdiEngine::DrawResource(const TRect&,const RDirectGdiDrawableSource&,const TRect&,DirectGdi::TGraphicsRotation) */ void CSwDirectGdiEngine::DrawResource( const TRect& aDestRect, const RDirectGdiDrawableSource& aSource, const TRect& aSrcRect, DirectGdi::TGraphicsRotation aRotation) { // pre: // aDestRect and aSrcRect are not empty // CSwDirectGdiImageSourceImpl* imgSrc = NULL; TSize imgSize; if (CheckImageSource(aSource.Handle(), imgSrc, &imgSize) != KErrNone) { return; } // check source rectangle is fully contained within the image resource extent if (aSrcRect.iTl.iX < 0 || aSrcRect.iTl.iY < 0 || aSrcRect.iBr.iX > imgSize.iWidth || aSrcRect.iBr.iY > imgSize.iHeight) { iDriver->SetError(KErrArgument); return; } DrawResourceCommon(aDestRect, imgSrc, aSrcRect, aRotation); } // // internal functions // /** Checks image resource is fully constructed and registered with the driver. @param aHandle A valid handle to an image source. @param aImg On return, contains the image source. @param aSize If not NULL, will contain the dimensions of the image source. @return KErrNone if successful, KErrBadHandle if aHandle is not a valid handle to an image source. */ TInt CSwDirectGdiEngine::CheckImageSource(TInt aHandle, CSwDirectGdiImageSourceImpl*& aImg, TSize* aSize) { // check image exist if (!iDriver->ValidImageSource(aHandle)) { // replace KErrNotFound const TInt err = KErrBadHandle; iDriver->SetError(err); return err; } aImg = reinterpret_cast<CSwDirectGdiImageSourceImpl*>(aHandle); // RSgImage cannot be created with zero size, so there is no point in validating its size and // simply return image size if requested if (aSize) { *aSize = aImg->Size(); } return KErrNone; } /** Implements common DrawResource() functionality used by all DrawResource() variants. */ void CSwDirectGdiEngine::DrawResourceCommon( const TRect& aDestRect, const CSwDirectGdiImageSourceImpl* aImg, const TRect& aSrcRect, DirectGdi::TGraphicsRotation aRotation) { // pre: // aDestRect and aSrcRect are not empty // aSrcRect is within the image extent // // translate relative coord to target absolute coord system TRect destRectAbs(aDestRect); destRectAbs.Move(iOrigin); // check whether we need to blend or write const TBool opaqueSource = (!PixelFormatUtil::HasAlpha(aImg->PixelFormat())) && (iDrawMode == DirectGdi::EDrawModePEN); if (opaqueSource) { iDrawMode = DirectGdi::EDrawModeWriteAlpha; } // repeat drawing op for each rectangle in the clipping region const TInt numOfRects = iDefaultRegionPtr->Count(); for (TInt idx = 0; idx < numOfRects; ++idx) { TRect clipRectAbs = (*iDefaultRegionPtr)[idx]; if (!clipRectAbs.Intersects(destRectAbs)) { continue; } // intersect current clip rect with dest rect to get actual draw area clipRectAbs.Intersection(destRectAbs); DoDrawResource(destRectAbs, aImg, aSrcRect, aRotation, clipRectAbs); iDrawDevice->UpdateRegion(clipRectAbs); } if (opaqueSource) { iDrawMode = DirectGdi::EDrawModePEN; } } /** Rotate a given rectangle 90 degree clockwise around the specified origin. */ void CSwDirectGdiEngine::Rotate90(TRect& aRect, const TPoint& aOrigin) { // rotated bottom-left become top-left of rotated rect // TPoint bl(aRect.iTl.iX, aRect.iBr.iY); const TInt w = aRect.Width(); const TInt h = aRect.Height(); const TPoint dbl = bl - aOrigin; bl.iX = aOrigin.iX - dbl.iY; bl.iY = aOrigin.iY + dbl.iX; aRect = TRect(bl, TSize(h,w)); } /** Rotate a given rectangle 180 degree clockwise around the specified origin. */ void CSwDirectGdiEngine::Rotate180(TRect& aRect, const TPoint& aOrigin) { // rotated bottom-right become top-left of rotated rect // TPoint br(aRect.iBr); const TSize sz = aRect.Size(); const TPoint dbr = br - aOrigin; br.iX = aOrigin.iX - dbr.iX; br.iY = aOrigin.iY - dbr.iY; aRect = TRect(br, sz); } /** Rotate a given rectangle 270 degree clockwise around the specified origin. */ void CSwDirectGdiEngine::Rotate270(TRect& aRect, const TPoint& aOrigin) { // rotated top-right become top-left of rotated rect // TPoint tr(aRect.iBr.iX, aRect.iTl.iY); const TInt w = aRect.Width(); const TInt h = aRect.Height(); const TPoint dtr = tr - aOrigin; tr.iX = aOrigin.iX + dtr.iY; tr.iY = aOrigin.iY - dtr.iX; aRect = TRect(tr, TSize(h,w)); } /** Tests that the size of a given rotated rectangle match the image source extent. */ TBool CSwDirectGdiEngine::RotatedSizeMatch(const TRect& aDst, const TRect& aSrc, DirectGdi::TGraphicsRotation aRot) { if (aRot==DirectGdi::EGraphicsRotationNone || aRot==DirectGdi::EGraphicsRotation180) { return aDst.Size()==aSrc.Size(); } else { return aDst.Width()==aSrc.Height() && aDst.Height()==aSrc.Width(); } } /** Draws a rectangular area of resource and apply rotation and/or scaling if requested. */ void CSwDirectGdiEngine::DoDrawResource( const TRect& aDestRectAbs, const CSwDirectGdiImageSourceImpl* aImg, const TRect& aSrcRect, DirectGdi::TGraphicsRotation aRotation, const TRect& aClipRectAbs) { // pre: // SetClippingRegion() already check that clipping region is always contained // within device full extent. // check src rect match the size of rotated dest rect if (RotatedSizeMatch(aDestRectAbs, aSrcRect, aRotation)) { // aClipRect is the effective drawing clipped area, it has been intersected with dest rect by the // calling function/DoDrawResourceCommon() and it is not empty when we reach here // image size has been checked at the top level DrawResource() no need to check it again // use aClipRect to determine how much area should be read from the image and transform // the effective read area into source rect depending on rotation parameter // start with aClipRect TRect xformSrcRect(aClipRectAbs); switch (aRotation) { case DirectGdi::EGraphicsRotationNone: // align top-left corner of dest rect with top-left corner of src rect xformSrcRect.Move(aSrcRect.iTl - aDestRectAbs.iTl); break; case DirectGdi::EGraphicsRotation90: { // align top-right corner of dest rect with top-left corner of src rect xformSrcRect.Move(aSrcRect.iTl - TPoint(aDestRectAbs.iBr.iX, aDestRectAbs.iTl.iY)); // rotate 270 (-90) degree using top-left corner of src rect as pivot point Rotate270(xformSrcRect, aSrcRect.iTl); } break; case DirectGdi::EGraphicsRotation180: { // align bottom-right corner of dest rect with top-left corner of src rect xformSrcRect.Move(aSrcRect.iTl - aDestRectAbs.iBr); // rotate 180 (-180) degree using top-left corner of src rect as pivot point Rotate180(xformSrcRect, aSrcRect.iTl); } break; case DirectGdi::EGraphicsRotation270: { // align bottom-left corner of dest rect with top-left corner of src rect xformSrcRect.Move(aSrcRect.iTl - TPoint(aDestRectAbs.iTl.iX, aDestRectAbs.iBr.iY)); // rotate 90 (-270) degree using top-left corner of src rect as pivot point Rotate90(xformSrcRect, aSrcRect.iTl); } break; // no need for extra check, aRotation has been checked at generic layer } DoBlitResource(aClipRectAbs.iTl, aImg, xformSrcRect, aRotation); return; } DoScaledBlitResource(aDestRectAbs, aImg, aSrcRect, aRotation, aClipRectAbs); } /** Draws a rectangular area of resource rotated with no scaling. @panic DGDIAdapter 1009, if the pixel format of the draw device is unknown (debug only). */ void CSwDirectGdiEngine::DoBlitResource( const TPoint& aDest, const CSwDirectGdiImageSourceImpl* aImg, const TRect& aSrcRect, DirectGdi::TGraphicsRotation aRotation) { // pre: // aDest is the top-left of clipped destination rectangle i.e. intersection of user destination // rectangle with current clipping rect // aSrcRect is rotated clipped read area i.e. effective read area with respect to original // image orientation i.e.it no longer represents user specified source rect. // no need to do extra check on parameters here because: // aDest is guaranteed to be within device drawing area // aSrcRect is guaranteed to be within image source area const TUidPixelFormat devFormat = PixelFormatUtil::ConvertToPixelFormat(iDrawDevice->DisplayMode()); GRAPHICS_ASSERT_DEBUG(devFormat != EUidPixelFormatUnknown, EDirectGdiPanicInvalidDisplayMode); const TUidPixelFormat imgFormat = aImg->PixelFormat(); const TUint32* imgAddr = reinterpret_cast<TUint32*>(aImg->DataBuffer()); const TInt imgStride = aImg->Stride(); const TSize imgSize = aImg->Size(); const CGraphicsContext::TDrawMode drawMode = GcDrawMode(iDrawMode); const TInt width = aSrcRect.Width(); const TInt height = aSrcRect.Height(); // write scanline starting from top dest row TInt destY = aDest.iY; // setup pixel reader toolkit TPixelBufferReader reader(imgAddr, imgSize, imgStride, imgFormat); TDrawDeviceWrapper writer(iDrawDevice, GcDrawMode(iDrawMode)); // // special case when rotation is none // if (aRotation == DirectGdi::EGraphicsRotationNone) { TAny* interface = NULL; // source and destination format match and using write alpha mode i.e. reduce blit to memcpy if (iDrawMode == DirectGdi::EDrawModeWriteAlpha && devFormat == imgFormat) { TInt err = iDrawDevice->GetInterface(KFastBlit2InterfaceID, interface); if (err == KErrNone) { GRAPHICS_ASSERT_DEBUG(interface, EDirectGdiPanicInvalidPointer); MFastBlit2* fblit = static_cast<MFastBlit2*>(interface); err = fblit->WriteBitmapBlock(aDest, imgAddr, imgStride, imgSize, aSrcRect); if (err == KErrNone) { return; } } } // fallback from MFastBlit2 when source and destination format match. // Note that there was previously an optimization added here that used MFlastBlend if // available, however it did not work correctly for some cases using DrawResource so has been // removed from this code. (A source drawn with OpenGLES on to a target in XRGB_8888 format // actually had alpha in the unused channel which was being drawn by MFastBlend) if (devFormat == imgFormat) { for (TInt row=aSrcRect.iTl.iY; row<aSrcRect.iBr.iY; ++row,++destY) { const TPoint pos(aSrcRect.iTl.iX, row); const TUint32* slptr = reader.GetPixelAddr(pos); writer.WriteLine(aDest.iX, destY, width, const_cast<TUint32*>(slptr), drawMode); } return; } // there is one additional case that can be optimised by eleminating copy when: // rotation : none // scaling : none // dst : opaque // src : has alpha and premultiplied // mode : PEN } // // generic cases // // copying is necessary either to convert pixel format or to read back buffer in reverse order // to achieve rotation // const TInt scanLineBytes = iDrawDevice->ScanLineBytes(); TUint32* scanLineBuffer = iDrawDevice->ScanLineBuffer(); TPtr8 scanLineDes(reinterpret_cast<TUint8*>(scanLineBuffer),scanLineBytes,scanLineBytes); // if destination is opaque e.g. RGB_565, XRGB_8888 and the source has alpha, it shall blend // (because iDrawMode is set to WritePEN) // we treat opaque destination as in pre-multiplied format (with alpha value 1), and read the // source in pre-multiplied format too, to enable optimum blending computation i.e. // "src + (1-alpha) * dst" const TUidPixelFormat readFormat = !PixelFormatUtil::HasAlpha(devFormat) && iDrawMode == DirectGdi::EDrawModePEN ? EUidPixelFormatARGB_8888_PRE : devFormat; if (aRotation == DirectGdi::EGraphicsRotationNone) { // general fallback from FastBlendBitmap // const TInt readLen = width; // normal read scanline, left to right // for (TInt row=aSrcRect.iTl.iY; row<aSrcRect.iBr.iY; ++row,++destY) { const TPoint pos(aSrcRect.iTl.iX, row); reader.GetScanLine(scanLineDes,pos, readLen, readFormat, TPixelBufferReader::EReadHorizontal); writer.WriteLine(aDest.iX, destY, readLen, scanLineBuffer, drawMode); } } else if (aRotation == DirectGdi::EGraphicsRotation90) { const TInt readLen = height; // read scanline vertically from bottom to up, and from the lef-most column // for (TInt col=aSrcRect.iTl.iX; col<aSrcRect.iBr.iX; ++col,++destY) { const TPoint pos(col, aSrcRect.iBr.iY-1); reader.GetScanLine(scanLineDes, pos, readLen, readFormat, TPixelBufferReader::EReadVerticalReverse); writer.WriteLine(aDest.iX, destY, readLen, scanLineBuffer, drawMode); } } else if (aRotation == DirectGdi::EGraphicsRotation180) { const TInt readLen = width; // read scanline from right to left, starting from the most bottom scanline // for (TInt row=aSrcRect.iBr.iY-1; row>=aSrcRect.iTl.iY; --row,++destY) { const TPoint pos(aSrcRect.iBr.iX-1, row); reader.GetScanLine(scanLineDes, pos, readLen, readFormat, TPixelBufferReader::EReadHorizontalReverse); writer.WriteLine(aDest.iX, destY, readLen, scanLineBuffer, drawMode); } } else if (aRotation == DirectGdi::EGraphicsRotation270) { const TInt readLen = height; // read scanline vertically top to bottom, and from the right-most column // for (TInt col=aSrcRect.iBr.iX-1; col>=aSrcRect.iTl.iX; --col,++destY) { const TPoint pos(col, aSrcRect.iTl.iY); reader.GetScanLine(scanLineDes, pos, readLen, readFormat, TPixelBufferReader::EReadVertical); writer.WriteLine(aDest.iX, destY, readLen, scanLineBuffer, drawMode); } } } /** Draws a rectangular area of resource rotated and/or scaled up/down. @panic DGDIAdapter 1009, if the pixel format of the draw device is unknown (debug only). */ void CSwDirectGdiEngine::DoScaledBlitResource( const TRect& aDestRectAbs, const CSwDirectGdiImageSourceImpl* aImg, const TRect& aSrcRect, DirectGdi::TGraphicsRotation aRotation, const TRect& aClipRectAbs) { // pre: // aDestRectAbs is the user specified dest rect that has been translated to target coord system. It may // be larger/outside the target drawing area. We must not modify this rect as it will be used to // determine the scaling factor. // aSrcRect is the user specified src rect, it is within the image extent. // aClipRectAbs is the intersection of current clipping rect and aDestRectAbs and is within the // target drawing area. const TUidPixelFormat devFormat = PixelFormatUtil::ConvertToPixelFormat(iDrawDevice->DisplayMode()); GRAPHICS_ASSERT_DEBUG(devFormat != EUidPixelFormatUnknown, EDirectGdiPanicInvalidDisplayMode); const TUint32* imgAddr = reinterpret_cast<TUint32*>(aImg->DataBuffer()); const TInt imgStride = aImg->Stride(); const TSize imgSize = aImg->Size(); const TUidPixelFormat imgFormat = aImg->PixelFormat(); const CGraphicsContext::TDrawMode drawMode = GcDrawMode(iDrawMode); // if destination is opaque e.g. RGB_565, XRGB_8888 and the source has alpha, it shall blend // (because iDrawMode is set to WritePEN) // we treat opaque destination as in pre-multiplied format (with alpha value 1), and read the // source in pre-multiplied format too, to enable optimum blending computation i.e. // "src + (1-alpha) * dst" const TUidPixelFormat readFormat = !PixelFormatUtil::HasAlpha(devFormat) && iDrawMode == DirectGdi::EDrawModePEN ? EUidPixelFormatARGB_8888_PRE : devFormat; TUint32* scanLineBuffer = iDrawDevice->ScanLineBuffer(); const TInt scanLineBytes = iDrawDevice->ScanLineBytes(); TPtr8 scanLineDes(reinterpret_cast<TUint8*>(scanLineBuffer), scanLineBytes, scanLineBytes); // setup pixel reader toolkit // TPixelBufferReader reader(imgAddr, imgSize, imgStride, imgFormat); TDrawDeviceWrapper writer(iDrawDevice, GcDrawMode(iDrawMode)); if (aRotation == DirectGdi::EGraphicsRotationNone) { // Note that there was previously an optimization added here that used MFlastBlend if // available, however it did not work correctly for some cases using DrawResource so has been // removed from this code. (A source drawn with OpenGLES on to a target in XRGB_8888 format // actually had alpha in the unused channel which was being drawn by MFastBlend) // const TInt srcLen = aSrcRect.Width(); const TInt destLen = aDestRectAbs.Width(); const TInt clipLen = aClipRectAbs.Width(); const TInt clipPos = aClipRectAbs.iTl.iX - aDestRectAbs.iTl.iX; // setup DDA for scaling in Y direction based on src rect and dst rect size // scaling in X direction will be done by GetScaledScanLine() // // setup Y scaler and start from top-left of src/dest to bottom-right of src/dest TLinearDDA yScaler; yScaler.Construct( TPoint(aSrcRect.iTl.iY, aDestRectAbs.iTl.iY), TPoint(aSrcRect.iBr.iY, aDestRectAbs.iBr.iY), TLinearDDA::ELeft); // move to position of current clip rect top row as the start of dest Y TInt srcY; yScaler.JumpToYCoord2(srcY, aClipRectAbs.iTl.iY); // yPos contains mapping between src Y (TPoint.iX) and dest Y (TPoint.iY) TPoint yPos(srcY, aClipRectAbs.iTl.iY); // write to target from top to bottom // while (yPos.iY < aClipRectAbs.iBr.iY) { reader.GetScaledScanLine(scanLineDes, TPoint(aSrcRect.iTl.iX, yPos.iX), // src X and Y clipPos, // clipped dest X clipLen, destLen, srcLen, readFormat, TPixelBufferReader::EReadHorizontal); // use dest Y here writer.WriteLine(aClipRectAbs.iTl.iX, yPos.iY, clipLen, scanLineBuffer, drawMode); // move scaler one position yScaler.NextStep(yPos); }; } else if (aRotation == DirectGdi::EGraphicsRotation90) { // we're going to read source vertically from bottom to up, swap relevant bits and pieces // dst-width corresponds to src-height // dst-height corresponds to src-width // const TInt srcLen = aSrcRect.Height(); const TInt destLen = aDestRectAbs.Width(); // the following doesn't change, the amount of pixel read (vertically) will be based on // the drawing area witdh i.e. clip width // const TInt clipLen = aClipRectAbs.Width(); // offset into read area doesn't change either, it will be translated into some Y position // from bottom row of source image const TInt clipPos = aClipRectAbs.iTl.iX - aDestRectAbs.iTl.iX; // setup DDA for scaling in src X direction based on src rect and dst rect size // scaling in src Y direction will be done by GetScaledScanLine(EReadVerticalReverse) // // scaler map dest Y to src X because of 90 degre rotation // start from top row dest, left-most column src to bottom row dest, right-most column src // TLinearDDA xScaler; xScaler.Construct( TPoint(aSrcRect.iTl.iX, aDestRectAbs.iTl.iY), TPoint(aSrcRect.iBr.iX, aDestRectAbs.iBr.iY), TLinearDDA::ELeft); // move to position of current clip rect top row as the start of src X TInt srcX; xScaler.JumpToYCoord2(srcX, aClipRectAbs.iTl.iY); // xPos contains mapping between src X (TPoint.iX) and dest Y (TPoint.iY) TPoint xPos(srcX, aClipRectAbs.iTl.iY); // write to target from top to bottom // while (xPos.iY < aClipRectAbs.iBr.iY) { // read pixel vertically from left column to right reader.GetScaledScanLine(scanLineDes, TPoint(xPos.iX, aSrcRect.iBr.iY - 1), // src X, src Y clipPos, // distance from bottom source clipLen, destLen, srcLen, readFormat, TPixelBufferReader::EReadVerticalReverse); // use dest Y here writer.WriteLine(aClipRectAbs.iTl.iX, xPos.iY, clipLen, scanLineBuffer, drawMode); // move scaler one position xScaler.NextStep(xPos); } } else if (aRotation == DirectGdi::EGraphicsRotation180) { const TInt srcLen = aSrcRect.Width(); const TInt destLen = aDestRectAbs.Width(); const TInt clipLen = aClipRectAbs.Width(); // clipPos doesn't need to be inverted (using iBr.iX) because the yScaler below // will do that for us (by stepping backward) // const TInt clipPos = aClipRectAbs.iTl.iX - aDestRectAbs.iTl.iX; // setup DDA for scaling in Y direction based on src rect and dst rect size // scaling in X direction will be done by GetScaledScanLine() // // setup Y scaler and start from bottom-right of src/dest to top-left of src/dest // to do backward stepping (src Y inversion) TLinearDDA yScaler; yScaler.Construct( // we starting from 1st pixel from bottom of source image, we need to // step back 1 position as bottom-row coord is beyond the last pixel in the source rect TPoint(aSrcRect.iBr.iY - 1, aDestRectAbs.iTl.iY), TPoint(aSrcRect.iTl.iY - 1, aDestRectAbs.iBr.iY), TLinearDDA::ELeft); // move to position of current clip rect top row as the start of dest Y // which will calculate inverted src Y distance from bottom of source rectangle TInt invSrcY; yScaler.JumpToYCoord2(invSrcY, aClipRectAbs.iTl.iY); // yPos contains mapping between inverted src Y (TPoint.iX) and dest Y (TPoint.iY) TPoint yPos(invSrcY, aClipRectAbs.iTl.iY); // write to target from top to bottom // while (yPos.iY < aClipRectAbs.iBr.iY) { // read scanline from righ to left i.e. use aSrcRect.iBr.iX-1 (last column) // as starting src X value reader.GetScaledScanLine(scanLineDes, TPoint(aSrcRect.iBr.iX - 1, yPos.iX), // src X and inverted src Y clipPos, // clipped dest X clipLen, destLen, srcLen, readFormat, TPixelBufferReader::EReadHorizontalReverse); // use dest Y here writer.WriteLine(aClipRectAbs.iTl.iX, yPos.iY, clipLen, scanLineBuffer, drawMode); // move scaler one position yScaler.NextStep(yPos); } } else if(aRotation == DirectGdi::EGraphicsRotation270) { // we're going to read source vertically from top to bottom, swap relevant bits and pieces // dst-width corresponds to src-height // dst-height corresponds to src-width const TInt srcLen = aSrcRect.Height(); const TInt destLen = aDestRectAbs.Width(); // the following doesn't change, the amount of pixel read (vertically) will be based on // the drawing area witdh i.e. clip width const TInt clipLen = aClipRectAbs.Width(); // offset into read area doesn't change either, it will be translated into some Y position // from top row of source image const TInt clipPos = aClipRectAbs.iTl.iX - aDestRectAbs.iTl.iX; // setup DDA for scaling in src X direction based on src rect and dst rect size // scaling in src Y direction will be done by GetScaledScanLine(EReadVertical) // // scaler map dest Y to src X because of 270 degre rotation // start from top row dest, right-most column src to bottom row dest, left-most column src TLinearDDA xScaler; xScaler.Construct( // decrement 1 pixel to get into last pixel within source TPoint(aSrcRect.iBr.iX - 1, aDestRectAbs.iTl.iY), TPoint(aSrcRect.iTl.iX - 1, aDestRectAbs.iBr.iY), TLinearDDA::ELeft); // move to position of current clip rect top row as the start of src X TInt srcX; xScaler.JumpToYCoord2(srcX, aClipRectAbs.iTl.iY); // xPos contains mapping between src X (TPoint.iX) and dest Y (TPoint.iY) TPoint xPos(srcX, aClipRectAbs.iTl.iY); // write to target from top to bottom // while (xPos.iY < aClipRectAbs.iBr.iY) { // read pixel vertically from left column to right reader.GetScaledScanLine(scanLineDes, TPoint(xPos.iX, aSrcRect.iTl.iY), // src X, src Y clipPos, // distance from bottom source clipLen, destLen, srcLen, readFormat, TPixelBufferReader::EReadVertical); // use dest Y here writer.WriteLine(aClipRectAbs.iTl.iX, xPos.iY, clipLen, scanLineBuffer, drawMode); // move scaler one position xScaler.NextStep(xPos); } } }