sl@0: // Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // sl@0: sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include "BITPANIC.H" sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: sl@0: /** sl@0: Draws a bitmap. sl@0: sl@0: The function has 3 overloads. The first draws the bitmap given the top sl@0: left hand corner, doing a compress/stretch based on its internally sl@0: stored size in twips. The second does a compress/stretch to fit a sl@0: given rectangle. The third takes a rectangular section of the source sl@0: bitmap and does a compress/stretch to fit a given destination sl@0: rectangle.The functions provide a concrete implementation of the pure sl@0: virtual function CGraphicsContext::DrawBitmap(). The sl@0: function behaviour is the same as documented in that class. sl@0: */ sl@0: EXPORT_C void CFbsBitGc::DrawBitmap(const TPoint& aPos,const CFbsBitmap* aSource) sl@0: { sl@0: if (aSource == NULL || !aSource->Handle()) sl@0: return; sl@0: sl@0: aSource->BeginDataAccess(); sl@0: const TSize bitmapTwips = aSource->SizeInTwips(); sl@0: if (bitmapTwips.iWidth == 0 || bitmapTwips.iHeight == 0) sl@0: { sl@0: aSource->EndDataAccess(ETrue); sl@0: return; sl@0: } sl@0: sl@0: TSize scrpixels; sl@0: scrpixels.iWidth = iDevice->HorizontalTwipsToPixels(bitmapTwips.iWidth); sl@0: scrpixels.iHeight = iDevice->VerticalTwipsToPixels(bitmapTwips.iHeight); sl@0: sl@0: DrawBitmap(TRect(aPos, scrpixels), aSource, TRect(aSource->SizeInPixels())); sl@0: aSource->EndDataAccess(ETrue); sl@0: } sl@0: sl@0: EXPORT_C void CFbsBitGc::DrawBitmap(const TRect& aDestRect,const CFbsBitmap* aSource) sl@0: { sl@0: if (aSource == NULL || !aSource->Handle()) sl@0: return; sl@0: sl@0: aSource->BeginDataAccess(); sl@0: DrawBitmap(aDestRect, aSource, TRect(aSource->SizeInPixels())); sl@0: aSource->EndDataAccess(ETrue); sl@0: } sl@0: sl@0: EXPORT_C void CFbsBitGc::DrawBitmap(const TRect& aDestRect, sl@0: const CFbsBitmap* aSource, sl@0: const TRect& aSourceRect) sl@0: { sl@0: if (CheckDevice(aDestRect) || aSourceRect.IsEmpty() || aSource == NULL || !aSource->Handle()) sl@0: return; sl@0: sl@0: aSource->BeginDataAccess(); sl@0: //aSourceRect should be in the bounds of the bitmap sl@0: TSize bitmapSize(aSource->SizeInPixels()); sl@0: if ( aSourceRect.iTl.iX < 0 sl@0: || aSourceRect.iTl.iY < 0 sl@0: || aSourceRect.iBr.iX > bitmapSize.iWidth sl@0: || aSourceRect.iBr.iY > bitmapSize.iHeight) sl@0: { sl@0: aSource->EndDataAccess(ETrue); sl@0: return; sl@0: } sl@0: sl@0: TRect destRect(aDestRect); sl@0: destRect.Move(iOrigin); sl@0: AddRect(destRect); sl@0: sl@0: TRect clippedDestRect(destRect); sl@0: if (UserClipRect(clippedDestRect)) sl@0: { sl@0: aSource->EndDataAccess(ETrue); sl@0: return; sl@0: } sl@0: sl@0: CFbsBitGcBitmap* srce = (CFbsBitGcBitmap*)aSource; sl@0: SetupDevice(); sl@0: iDevice->DrawingBegin(); sl@0: sl@0: CBitwiseBitmap* bmp = srce->Address(); sl@0: BG_ASSERT_DEBUG(bmp,EBitgdiPanicInvalidBitmap); sl@0: sl@0: CFbsRasterizer* rasterizer = PrepareRasterizerForExtendedBitmap(*aSource, destRect, aSourceRect); sl@0: sl@0: const TPoint ditherOrigin(iDitherOrigin + aDestRect.iTl); sl@0: sl@0: const TInt limit = iDefaultRegionPtr->Count(); sl@0: CGraphicsAccelerator* ga = GraphicsAccelerator(); sl@0: if (ga && iShadowMode==CFbsDrawDevice::ENoShadow && iDrawMode==EDrawModePEN) sl@0: { sl@0: TInt gaOperationResult = KErrUnknown; sl@0: TAcceleratedBitmapSpec bitmapSpec(const_cast(aSource)); sl@0: iDevice->DrawingEnd(); sl@0: sl@0: if (destRect.Size() == aSourceRect.Size()) sl@0: { sl@0: const TPoint offset(aSourceRect.iTl - destRect.iTl); sl@0: for(TInt count=0;countOperation(TGopBitBlt(iClipRect.iTl,bitmapSpec,clippedSrceRect)); sl@0: if (gaOperationResult!=KErrNone) sl@0: break; sl@0: } sl@0: iDevice->iDrawDevice->UpdateRegion(iClipRect); sl@0: } sl@0: else sl@0: { sl@0: RRegion clippedRegion; sl@0: for(TInt clipIt=0;clipItOperation(TGopScaledBitBlt(destRect,bitmapSpec,srcCopy),clippedRegion.Count(),const_cast(clippedRegion.RectangleList())); sl@0: if (gaOperationResult==KErrNone) sl@0: iDevice->iDrawDevice->Update(clippedRegion); sl@0: clippedRegion.Close(); sl@0: } sl@0: if(gaOperationResult == KErrNone) sl@0: goto finish; sl@0: iDevice->DrawingBegin(); sl@0: sl@0: } sl@0: // sl@0: { // to stop error from gccxml build about previous jump to finish skipping initialisation of opaqueSource sl@0: const TBool opaqueSource = (!IsAlphaChannel(aSource->DisplayMode())) && (iDrawMode == EDrawModePEN); sl@0: if (opaqueSource) sl@0: { sl@0: iDrawMode = EDrawModeWriteAlpha; sl@0: } sl@0: sl@0: for (TInt count = 0; count < limit; count++) sl@0: { sl@0: iClipRect = (*iDefaultRegionPtr)[count]; sl@0: if (!iClipRect.Intersects(clippedDestRect)) sl@0: continue; sl@0: sl@0: iClipRect.Intersection(clippedDestRect); sl@0: DoDrawBitmap(destRect,bmp,aSource->DataAddress(),aSource->DataStride(),aSourceRect,ditherOrigin); sl@0: sl@0: iDevice->iDrawDevice->UpdateRegion(iClipRect); sl@0: } sl@0: if (opaqueSource) sl@0: { sl@0: iDrawMode = EDrawModePEN; sl@0: } sl@0: sl@0: } sl@0: iDevice->DrawingEnd(); sl@0: sl@0: finish: sl@0: if (rasterizer) sl@0: { sl@0: rasterizer->EndBitmap(aSource->SerialNumber()); sl@0: } sl@0: aSource->EndDataAccess(ETrue); sl@0: } sl@0: sl@0: sl@0: void CFbsBitGc::DoDrawBitmap(const TRect& aDestRect, sl@0: CBitwiseBitmap* aBitmap, sl@0: TUint32* aBase, sl@0: TInt aStride, sl@0: const TRect& aSrceRect, sl@0: const TPoint& aDitherOrigin) sl@0: { sl@0: CFbsDrawDevice* drawDevice = iDevice->iDrawDevice; sl@0: #ifdef _DEBUG sl@0: TRect deviceDestRect; sl@0: drawDevice->GetDrawRect(deviceDestRect); sl@0: #endif sl@0: BG_ASSERT_DEBUG(iClipRect.iTl.iX >= deviceDestRect.iTl.iX, EBitgdiPanicOutOfBounds); sl@0: BG_ASSERT_DEBUG(iClipRect.iTl.iY >= deviceDestRect.iTl.iY, EBitgdiPanicOutOfBounds); sl@0: BG_ASSERT_DEBUG(iClipRect.iBr.iX <= deviceDestRect.iBr.iX, EBitgdiPanicOutOfBounds); sl@0: BG_ASSERT_DEBUG(iClipRect.iBr.iY <= deviceDestRect.iBr.iY, EBitgdiPanicOutOfBounds); sl@0: sl@0: if (aDestRect.Size() == aSrceRect.Size()) sl@0: { sl@0: TRect clippedRect(aDestRect); sl@0: clippedRect.Intersection(iClipRect); sl@0: sl@0: if (!clippedRect.IsEmpty()) sl@0: { sl@0: const TPoint destPoint(clippedRect.iTl); sl@0: clippedRect.Move(aSrceRect.iTl - aDestRect.iTl); sl@0: DoBitBlt(destPoint,aBitmap,aBase,aStride,clippedRect); sl@0: } sl@0: sl@0: return; sl@0: } sl@0: MFastBlend* fastBlend=NULL; sl@0: if (FastBlendInterface(aBitmap,NULL,fastBlend)==KErrNone) sl@0: { sl@0: if (fastBlend->FastBlendBitmapScaled(iClipRect, aDestRect, aSrceRect, aBase, aStride, aBitmap->DisplayMode(), aBitmap->SizeInPixels(), iDrawMode, iShadowMode)== KErrNone) sl@0: { sl@0: return; sl@0: } sl@0: } sl@0: sl@0: TUint32* scanLineBuffer = drawDevice->ScanLineBuffer(); sl@0: const TInt scanLineBytes = drawDevice->ScanLineBytes(); sl@0: TPtr8 scanLineDes(REINTERPRET_CAST(TUint8*,scanLineBuffer),scanLineBytes,scanLineBytes); sl@0: sl@0: // For EColor16MU targets, don't use EColor16MAP when draw mode is EDrawModeWriteAlpha. sl@0: // Format conversion provides no performance gain and WriteLine expects EColor16MU sl@0: // in this case. sl@0: const TDisplayMode dispMode = drawDevice->DisplayMode() == EColor16MU && iDrawMode == EDrawModeWriteAlpha ? EColor16MU : drawDevice->ScanLineDisplayMode(); sl@0: sl@0: TLinearDDA xLine; sl@0: TInt bitmapXStart = 0; sl@0: xLine.Construct(TPoint(aSrceRect.iTl.iX,aDestRect.iTl.iX), sl@0: TPoint(aSrceRect.iBr.iX,aDestRect.iBr.iX),TLinearDDA::ELeft); sl@0: xLine.JumpToYCoord(bitmapXStart,iClipRect.iTl.iX); sl@0: sl@0: TLinearDDA yLine; sl@0: TPoint yCoord(aSrceRect.iTl.iY,aDestRect.iTl.iY); sl@0: yLine.Construct(yCoord,TPoint(aSrceRect.iBr.iY,aDestRect.iBr.iY),TLinearDDA::ELeft); sl@0: TInt dummy; sl@0: yLine.JumpToYCoord2(dummy,iClipRect.iTl.iY); sl@0: yCoord.SetXY(dummy,iClipRect.iTl.iY); sl@0: sl@0: TBool finished = EFalse; sl@0: TPoint ditherOrigin(aDitherOrigin + iClipRect.iTl); sl@0: const TInt srceWidth = aSrceRect.Width(); sl@0: const TInt destWidth = aDestRect.Width(); sl@0: const TInt clipWidth = iClipRect.Width(); sl@0: const TInt clipStrch = iClipRect.iTl.iX - aDestRect.iTl.iX; sl@0: sl@0: TLineScanningPosition lineScanPos(aBase); sl@0: while (yCoord.iY < iClipRect.iBr.iY && !finished) sl@0: { sl@0: aBitmap->StretchScanLine(scanLineDes,TPoint(bitmapXStart,yCoord.iX), sl@0: clipStrch,clipWidth,destWidth,aSrceRect.iTl.iX, sl@0: srceWidth,ditherOrigin,dispMode,aBase,lineScanPos); sl@0: if (yCoord.iY==iClipRect.iTl.iY) sl@0: aBitmap->SetCompressionBookmark(lineScanPos, aBase,NULL); sl@0: drawDevice->WriteLine(iClipRect.iTl.iX,yCoord.iY,clipWidth, scanLineBuffer,iDrawMode); sl@0: finished = yLine.NextStep(yCoord); sl@0: ditherOrigin.iY++; sl@0: } sl@0: } sl@0: sl@0: /** The method draws a specified rectangle from a bitmap and sl@0: its mask into another rectangle and does a compress/stretch sl@0: to fit a given destination rectangle. sl@0: sl@0: @note When using this function with a 256 Mask bitmap, it blends. sl@0: Otherwise (e.g. with a 4bpp mask), this function masks rather than blends. sl@0: If a user wants to blend the source into the destination they should use sl@0: CFbsBitGc::AlphaBlendBitmaps() instead. sl@0: sl@0: @publishedAll sl@0: @released sl@0: sl@0: @param aDestRect The rectangle within which the masked bitmap is to be drawn. sl@0: @param aBitmap A pointer to the source bitmap. sl@0: @param aSourceRect The rectangle in the source bitmap that is copied to the sl@0: destination rectangle. sl@0: @param aMaskBitmap A pointer to the mask bitmap. sl@0: @param aInvertMask If false, a source pixel that is masked by a black pixel sl@0: is not transferred to the destination rectangle. If true, then a source pixel sl@0: that is masked by a white pixel is not transferred to the destination rectangle. sl@0: sl@0: @pre aBitmap != NULL sl@0: @pre aBitmap->Handle() != 0 sl@0: @pre aMaskBitmap != NULL sl@0: @pre aMaskBitmap->Handle() != 0 sl@0: @pre !aSourceRect.IsEmpty() sl@0: @pre aSourceRect should be in the bounds of the bitmap sl@0: */ sl@0: EXPORT_C void CFbsBitGc::DrawBitmapMasked(const TRect& aDestRect, sl@0: const CFbsBitmap* aBitmap, sl@0: const TRect& aSourceRect, sl@0: const CFbsBitmap* aMaskBitmap, sl@0: TBool aInvertMask) sl@0: { sl@0: if (aBitmap == NULL || !aBitmap->Handle() || aMaskBitmap == NULL || sl@0: !aMaskBitmap->Handle() || aSourceRect.IsEmpty() || CheckDevice(aDestRect)) sl@0: { sl@0: return; sl@0: } sl@0: sl@0: aBitmap->BeginDataAccess(); sl@0: aMaskBitmap->BeginDataAccess(); sl@0: sl@0: //aSourceRect should be in the bounds of the bitmap sl@0: TSize bitmapSize(aBitmap->SizeInPixels()); sl@0: if ( aSourceRect.iTl.iX < 0 sl@0: || aSourceRect.iTl.iY < 0 sl@0: || aSourceRect.iBr.iX > bitmapSize.iWidth sl@0: || aSourceRect.iBr.iY > bitmapSize.iHeight) sl@0: { sl@0: aBitmap->EndDataAccess(ETrue); sl@0: aMaskBitmap->EndDataAccess(ETrue); sl@0: return; sl@0: } sl@0: sl@0: TRect destRect(aDestRect); sl@0: destRect.Move(iOrigin); sl@0: AddRect(destRect); sl@0: TRect clippedDestRect(destRect); sl@0: if (UserClipRect(clippedDestRect)) sl@0: { sl@0: aBitmap->EndDataAccess(ETrue); sl@0: aMaskBitmap->EndDataAccess(ETrue); sl@0: return; sl@0: } sl@0: sl@0: SetupDevice(); sl@0: const TBool opaqueSource = (!IsAlphaChannel(aBitmap->DisplayMode())) && (iDrawMode == EDrawModePEN); sl@0: iDevice->DrawingBegin(); sl@0: sl@0: CBitwiseBitmap* srcebmp = ((CFbsBitGcBitmap*)aBitmap)->Address(); sl@0: CBitwiseBitmap* maskbmp = ((CFbsBitGcBitmap*)aMaskBitmap)->Address(); sl@0: BG_ASSERT_DEBUG(srcebmp,EBitgdiPanicInvalidBitmap); sl@0: BG_ASSERT_DEBUG(maskbmp,EBitgdiPanicInvalidBitmap); sl@0: sl@0: CFbsRasterizer* rasterizer = PrepareRasterizerForExtendedBitmap(*aBitmap, destRect, aSourceRect); sl@0: CFbsRasterizer* maskRasterizer = NULL; sl@0: if (srcebmp != maskbmp) sl@0: { sl@0: if (aMaskBitmap->SizeInPixels().iWidth >= aBitmap->SizeInPixels().iWidth sl@0: && aMaskBitmap->SizeInPixels().iHeight >= aBitmap->SizeInPixels().iHeight) sl@0: { sl@0: // Mask is not tiled. Pass same region of interest as source bitmap to rasterizer. sl@0: maskRasterizer = PrepareRasterizerForExtendedBitmap(*aMaskBitmap, destRect, aSourceRect); sl@0: } sl@0: else sl@0: { sl@0: // Mask is tiled. Do not pass any region of interest to rasterizer. sl@0: maskRasterizer = PrepareRasterizerForExtendedBitmap(*aMaskBitmap); sl@0: } sl@0: } sl@0: sl@0: const TPoint ditherOrigin(iDitherOrigin + aDestRect.iTl); sl@0: const TInt limit = iDefaultRegionPtr->Count(); sl@0: // sl@0: CGraphicsAccelerator* ga = GraphicsAccelerator(); sl@0: if (ga && iShadowMode==CFbsDrawDevice::ENoShadow && (aMaskBitmap->DisplayMode()!=EGray2 || !aInvertMask) && iDrawMode==EDrawModePEN) sl@0: { sl@0: TInt gaOperationResult = KErrUnknown; sl@0: TAcceleratedBitmapSpec bitmapSpec(const_cast(aBitmap)); sl@0: iDevice->DrawingEnd(); sl@0: TAcceleratedBitmapSpec maskSpec(const_cast(aMaskBitmap)); sl@0: const TPoint offset(aSourceRect.iTl - destRect.iTl); sl@0: sl@0: if (destRect.Size() == aSourceRect.Size()) sl@0: { sl@0: for(TInt count=0;countOperation(TGopBitBltMasked(iClipRect.iTl,bitmapSpec,clippedSrceRect,maskSpec)); sl@0: if (gaOperationResult!=KErrNone) sl@0: break; sl@0: iDevice->iDrawDevice->UpdateRegion(iClipRect); sl@0: } sl@0: } sl@0: else sl@0: { sl@0: RRegion clippedRegion; sl@0: for(TInt clipIt=0;clipItOperation(TGopScaledBitBltMasked(destRect,bitmapSpec,srcCopy,maskSpec),clippedRegion.Count(),const_cast(clippedRegion.RectangleList())); sl@0: if (gaOperationResult==KErrNone) sl@0: iDevice->iDrawDevice->Update(clippedRegion); sl@0: clippedRegion.Close(); sl@0: } sl@0: if (gaOperationResult==KErrNone) sl@0: goto finish; sl@0: iDevice->DrawingBegin(); sl@0: } sl@0: // sl@0: if (opaqueSource) sl@0: iDrawMode = EDrawModeWriteAlpha; sl@0: for (TInt count = 0; count < limit; count++) sl@0: { sl@0: iClipRect = (*iDefaultRegionPtr)[count]; sl@0: if (!iClipRect.Intersects(clippedDestRect)) sl@0: continue; sl@0: iClipRect.Intersection(clippedDestRect); sl@0: DoDrawBitmapMasked(destRect, sl@0: srcebmp, sl@0: aBitmap->DataAddress(), sl@0: aSourceRect, sl@0: maskbmp, sl@0: aMaskBitmap->DataAddress(), sl@0: aInvertMask, ditherOrigin); sl@0: iDevice->iDrawDevice->UpdateRegion(iClipRect); sl@0: } sl@0: if (opaqueSource) sl@0: iDrawMode = EDrawModePEN; sl@0: iDevice->DrawingEnd(); sl@0: finish: sl@0: if (rasterizer) sl@0: { sl@0: rasterizer->EndBitmap(aBitmap->SerialNumber()); sl@0: } sl@0: if (maskRasterizer) sl@0: { sl@0: maskRasterizer->EndBitmap(aMaskBitmap->SerialNumber()); sl@0: } sl@0: aBitmap->EndDataAccess(ETrue); sl@0: aMaskBitmap->EndDataAccess(ETrue); sl@0: } sl@0: sl@0: /** The method draws a specified rectangle from a bitmap and sl@0: its mask into another rectangle and does a compress/stretch sl@0: to fit a given destination rectangle. sl@0: sl@0: This is an overload, which takes CWsBitmap* as argument, which sl@0: in turn calls the other overload. sl@0: sl@0: Note: A pointer to CWsBitmap must have the same pointer value as a pointer sl@0: to the associated CFbsBitmap, otherwise code in BitGdi component will be sl@0: Broken. sl@0: sl@0: @note When using this function with a 256 Mask bitmap, it blends. sl@0: Otherwise (e.g. with a 4bpp mask), this function masks rather than blends. sl@0: If a user wants to blend the source into the destination they should use sl@0: CFbsBitGc::AlphaBlendBitmaps() instead. sl@0: sl@0: @publishedAll sl@0: @released sl@0: sl@0: @param aDestRect The rectangle within which the masked bitmap is to be drawn. sl@0: @param aBitmap A pointer to the source bitmap. sl@0: @param aSourceRect The rectangle in the source bitmap that is copied to the sl@0: destination rectangle. sl@0: @param aMaskBitmap A pointer to the mask bitmap. sl@0: @param aInvertMask If false, a source pixel that is masked by a black pixel sl@0: is not transferred to the destination rectangle. If true, then a source pixel sl@0: that is masked by a white pixel is not transferred to the destination rectangle. sl@0: sl@0: @pre aBitmap != NULL sl@0: @pre aBitmap->Handle() != 0 sl@0: @pre aMaskBitmap != NULL sl@0: @pre aMaskBitmap->Handle() != 0 sl@0: @pre !aSourceRect.IsEmpty() sl@0: */ sl@0: EXPORT_C void CFbsBitGc::DrawBitmapMasked(const TRect& aDestRect, sl@0: const CWsBitmap* aBitmap, sl@0: const TRect& aSourceRect, sl@0: const CWsBitmap* aMaskBitmap, sl@0: TBool aInvertMask) sl@0: { sl@0: DrawBitmapMasked(aDestRect,REINTERPRET_CAST(const CFbsBitmap*,aBitmap),aSourceRect,REINTERPRET_CAST(const CFbsBitmap*,aMaskBitmap),aInvertMask); sl@0: }