diff -r 000000000000 -r 40261b775718 mmplugins/imagingplugins/codecs/WMFCodec/WMFCodec.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mmplugins/imagingplugins/codecs/WMFCodec/WMFCodec.cpp Tue Feb 02 01:56:55 2010 +0200 @@ -0,0 +1,2377 @@ +// Copyright (c) 1999-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 +#include +#include "WMFCodec.h" + +/* +Not supported: +0) Misc + // 0x0105 - SETRELABS + // 0x0231 - SETMAPPERFLAGS + // 0x0419 - FLOODFILL + // 0x0548 - EXTFLOODFILL + // 0x0626 - ESCAPE + // 0x0830 - CHORD +1) Blitting + // 0x0107 - SETSTRETCHBLTMODE + // 0x0922 - BITBLT + // 0x0940 - DIBBITBLT + // 0x0b23 - STRETCHBLT + // 0x0d33 - SETDIBTODEV +2) Clipping + // 0x0220 - OFFSETCLIPRGN + // 0x0415 - EXCLUDECLIPRECT +3) Palettes + // 0x0035 - REALIZEPALETTE + // 0x0037 - SETPALENTRIES + // 0x00f7 - CREATEPALETTE + // 0x0139 - RESIZEPALETTE + // 0x0234 - SELECTPALETTE + // 0x0436 - ANIMATEPALETTE +*/ + +const TInt KFontNormalWeightLimit = 550; // Halfway between FW_NORMAL and FW_BOLD +const TInt KFontFixedPitch = 1; // FIXED_PITCH +const TInt KFontFamilyRoman = 1; // FF_ROMAN +const TInt KFontFamilySwiss = 2; // FF_SWISS +const TInt KFontFamilyMono = 3; // FF_MODERN +const TInt KFontFamilyScript = 4; // FF_SCRIPT +const TInt KFontFamilyDecorative = 5; // FF_DECORATIVE + +const TInt KExtTextOutFlagClipped = 4; // ETO_CLIPPED + +//const TInt KTextAlignFlagNoUpdateCP = 0; // EABI warning removal +//const TInt KTextAlignFlagUpdateCP = 1; // Not supported // EABI warning removal +//const TInt KTextAlignFlagLeft = 0; // EABI warning removal +const TInt KTextAlignFlagRight = 2; +const TInt KTextAlignFlagCenter = 6; +//const TInt KTextAlignFlagTop = 0; // EABI warning removal +const TInt KTextAlignFlagBottom = 8; +const TInt KTextAlignFlagBaseline = 24; + +const TInt KTextAlignMaskHorz = 6; +const TInt KTextAlignMaskVert = 24; + +const TUint KMaxProcessTime = 175000; //limit DoProcessL() to 175ms for liveliness + +// Wrapper class for drawing to the bitmap. +// All drawing operations go through this class. +CFbsBitGcWrapper* CFbsBitGcWrapper::NewL(CFbsDevice& aDevice, CFbsBitGcWrapper* aGc) + { + CFbsBitGcWrapper* self = new(ELeave) CFbsBitGcWrapper; + + CleanupStack::PushL(self); + self->ConstructL(aDevice, aGc); + CleanupStack::Pop(self); + return self; + } + +CFbsBitGcWrapper::CFbsBitGcWrapper(): + iBrushColor(KRgbWhite), + iBrushStyle(CGraphicsContext::ENullBrush), + iPenColor(KRgbBlack), + iPenStyle(CGraphicsContext::ESolidPen), + iPenSize(1,1), + iTextColor(KRgbBlack), + iBackgroundColor(KRgbWhite) + {} + +void CFbsBitGcWrapper::ConstructL(CFbsDevice& aDevice, CFbsBitGcWrapper* aGc) + { + User::LeaveIfError(aDevice.CreateContext(iGc)); + User::LeaveIfError(aDevice.CreateContext(iPolygonGc)); + if (aGc) + { + iGc->CopySettings(*(aGc->iGc)); + iGc->CancelClippingRegion(); + + iPolygonGc->CopySettings(*(aGc->iGc)); + iPolygonGc->CancelClippingRegion(); + + iBrushColor = aGc->iBrushColor; + iBrushStyle = aGc->iBrushStyle; + iPenColor = aGc->iPenColor; + iPenStyle = aGc->iPenStyle; + iPenSize = aGc->iPenSize; + + iTextColor = aGc->iTextColor; + iBackgroundColor = aGc->iBackgroundColor; + iPatternBrush = aGc->iPatternBrush; + } + } + +CFbsBitGcWrapper::~CFbsBitGcWrapper() + { + delete iGc; + delete iPolygonGc; + } + +void CFbsBitGcWrapper::SetPen(const CPen& aPen) + { + iPenStyle = aPen.iStyle; + iPenSize = aPen.iSize; + iPenColor = aPen.iColor; + + iGc->SetPenStyle(iPenStyle); + iGc->SetPenSize(iPenSize); + iGc->SetPenColor(iPenColor); + } + +void CFbsBitGcWrapper::SetBrush(CBrush& aBrush) + { + iBrushColor = aBrush.iColor; + iBrushStyle = aBrush.iStyle; + iPatternBrush = (iBrushStyle == CGraphicsContext::EPatternedBrush) ? static_cast (&aBrush) : NULL; + + iGc->SetBrushStyle(iBrushStyle); + iGc->SetBrushColor(iBrushColor); + } + +void CFbsBitGcWrapper::RestorePenAndBrush() + { + iGc->SetPenStyle(iPenStyle); + iGc->SetPenSize(iPenSize); + iGc->SetPenColor(iPenColor); + + iGc->SetBrushStyle(iBrushStyle); + iGc->SetBrushColor(iBrushColor); + } + +void CFbsBitGcWrapper::DrawPolygonL(const TPoint* aPointList,TInt aNumPoints,CGraphicsContext::TFillRule aFillRule) + { + RealizeBrush(); + if (iPenStyle == CGraphicsContext::ENullPen || iPenSize.iWidth == 0) + { + if (iBrushStyle != CGraphicsContext::ENullBrush) + { + iPolygonGc->CopySettings(*iGc); + iPolygonGc->CancelClippingRegion(); + + iPolygonGc->SetPenStyle(CGraphicsContext::ESolidPen); + iPolygonGc->SetPenSize(TSize(1,1)); + iPolygonGc->SetPenColor(iBrushColor); + + User::LeaveIfError(iPolygonGc->DrawPolygon(aPointList,aNumPoints,aFillRule)); + } + } + else + User::LeaveIfError(iGc->DrawPolygon(aPointList,aNumPoints,aFillRule)); + } + +const CFbsFont* CFbsBitGcWrapper::CurrentFont() + { + return iCurrentFont; + } + +void CFbsBitGcWrapper::Clear() + { + iGc->Clear(); + } + +void CFbsBitGcWrapper::SetUnderlineStyle(TFontUnderline aUnderlineStyle) + { + iGc->SetUnderlineStyle(aUnderlineStyle); + } + +void CFbsBitGcWrapper::SetStrikethroughStyle(TFontStrikethrough aStrikethroughStyle) + { + iGc->SetStrikethroughStyle(aStrikethroughStyle); + } + +void CFbsBitGcWrapper::UseFont(const CFbsFont* aFont) + { + iGc->UseFont(aFont); + iCurrentFont = aFont; + } + +void CFbsBitGcWrapper::SetClippingRegion(const TRegion* aRegion) + { + iGc->SetClippingRegion(aRegion); + } + +void CFbsBitGcWrapper::SetCharJustification(TInt aExcessWidth, TInt aNumGaps) + { + iGc->SetCharJustification(aExcessWidth, aNumGaps); + } + +void CFbsBitGcWrapper::SetWordJustification(TInt aExcessWidth, TInt aNumChars) + { + iGc->SetWordJustification(aExcessWidth, aNumChars); + } + +void CFbsBitGcWrapper::DrawLineTo(const TPoint& aPoint) + { + iGc->DrawLineTo(aPoint); + } + +void CFbsBitGcWrapper::MoveTo(const TPoint& aPoint) + { + iGc->MoveTo(aPoint); + } + +void CFbsBitGcWrapper::DrawPolyLine(const TPoint* aPointList, TInt aNumPoints) + { + iGc->DrawPolyLine(aPointList, aNumPoints); + } + +void CFbsBitGcWrapper::DrawEllipse(const TRect& aRect) + { + RealizeBrush(); + iGc->DrawEllipse(aRect); + } + +void CFbsBitGcWrapper::DrawRect(const TRect& aRect) + { + RealizeBrush(); + iGc->DrawRect(aRect); + } + +void CFbsBitGcWrapper::DrawRoundRect(const TRect& aRect, const TSize& aEllipse) + { + RealizeBrush(); + iGc->DrawRoundRect(aRect, aEllipse); + } + +void CFbsBitGcWrapper::SetPenStyle(CGraphicsContext::TPenStyle aPenStyle) + { + iGc->SetPenStyle(aPenStyle); + } + +void CFbsBitGcWrapper::SetBrushStyle(CGraphicsContext::TBrushStyle aBrushStyle) + { + iGc->SetBrushStyle(aBrushStyle); + } + +void CFbsBitGcWrapper::SetBrushColor(const TRgb& aColor) + { + iGc->SetBrushColor(aColor); + } + +void CFbsBitGcWrapper::SetDrawMode(CGraphicsContext::TDrawMode aDrawMode) + { + iGc->SetDrawMode(aDrawMode); + } + +void CFbsBitGcWrapper::SetPenColor(const TRgb& aColor) + { + iGc->SetPenColor(aColor); + } + +void CFbsBitGcWrapper::SetTextPenColor() + { + iGc->SetPenColor(iTextColor); + } + +void CFbsBitGcWrapper::Plot(const TPoint& aPoint) + { + iGc->Plot(aPoint); + } + +void CFbsBitGcWrapper::SetPenSize(const TSize& aSize) + { + iGc->SetPenSize(aSize); + } + + +void CFbsBitGcWrapper::DrawArc(const TRect& aRect, const TPoint& aStart, const TPoint& aEnd) + { + iGc->DrawArc(aRect, aStart, aEnd); + } + +void CFbsBitGcWrapper::DrawPie(const TRect& aRect, const TPoint& aStart, const TPoint& aEnd) + { + RealizeBrush(); + iGc->DrawPie(aRect, aStart, aEnd); + } + +void CFbsBitGcWrapper::DrawBitmap(const TRect& aDestRect, const CFbsBitmap* aSource, const TRect& aSourceRect) + { + iGc->DrawBitmap(aDestRect, aSource, aSourceRect); + } + +void CFbsBitGcWrapper::DrawText(const TDesC& aText,const TPoint& aPosition) + { + iGc->DrawText(aText, aPosition); + } + +void CFbsBitGcWrapper::UseBrushPattern(const CFbsBitmap* aPatternBitmap) + { + iGc->UseBrushPattern(aPatternBitmap); + } + +void CFbsBitGcWrapper::SetBackgroundColor(TRgb aBackgroundColor) + { + iBackgroundColor = aBackgroundColor; + } + +void CFbsBitGcWrapper::SetTextColor(TRgb aTextColor) + { + iTextColor = aTextColor; + } + +void CFbsBitGcWrapper::RealizeBrush() + { + if (iPatternBrush) + iPatternBrush->RealizeBrush(iTextColor, iBackgroundColor); + } + +// Wrapper class for drawing to the bitmap and mask. +// All drawing operations are performed through this class when mask generation is requested. +CFbsBitGcMaskWrapper* CFbsBitGcMaskWrapper::NewL(CFbsDevice& aDevice, CFbsDevice& aMaskDevice, CFbsBitGcMaskWrapper* aGc) + { + CFbsBitGcMaskWrapper* self = new(ELeave) CFbsBitGcMaskWrapper; + + CleanupStack::PushL(self); + self->ConstructL(aDevice, aMaskDevice, aGc); + CleanupStack::Pop(self); + return self; + } + +CFbsBitGcMaskWrapper::CFbsBitGcMaskWrapper() + { + } + +void CFbsBitGcMaskWrapper::ConstructL(CFbsDevice& aDevice, CFbsDevice& aMaskDevice, CFbsBitGcMaskWrapper* aGc) + { + CFbsBitGcWrapper::ConstructL(aDevice, aGc); + User::LeaveIfError(aMaskDevice.CreateContext(iMaskGc)); + User::LeaveIfError(aMaskDevice.CreateContext(iPolygonMaskGc)); + if (aGc) + { + iMaskGc->CopySettings(*(aGc->iMaskGc)); + iMaskGc->CancelClippingRegion(); + + iPolygonMaskGc->CopySettings(*(aGc->iMaskGc)); + iPolygonMaskGc->CancelClippingRegion(); + } + + // Set the pen color to white. + // (Ensures that all drawing operations will set pixels on the mask) + iMaskGc->SetPenColor(KRgbWhite); + iPolygonMaskGc->SetPenColor(KRgbWhite); + } + +CFbsBitGcMaskWrapper::~CFbsBitGcMaskWrapper() + { + delete iMaskGc; + delete iPolygonMaskGc; + } + +void CFbsBitGcMaskWrapper::SetPen(const CPen& aPen) + { + CFbsBitGcWrapper::SetPen(aPen); + + iMaskGc->SetPenStyle(iPenStyle); + iMaskGc->SetPenSize(iPenSize); + } + +void CFbsBitGcMaskWrapper::SetBrush(CBrush& aBrush) + { + CFbsBitGcWrapper::SetBrush(aBrush); + + if (!iPatternBrush) + iMaskGc->SetBrushStyle(iBrushStyle); + else + iMaskGc->SetBrushStyle(CGraphicsContext::ESolidBrush); + } + +void CFbsBitGcMaskWrapper::DrawPolygonL(const TPoint* aPointList,TInt aNumPoints,CGraphicsContext::TFillRule aFillRule) + { + CFbsBitGcWrapper::DrawPolygonL(aPointList, aNumPoints, aFillRule); + if (iPenStyle == CGraphicsContext::ENullPen || iPenSize.iWidth == 0) + { + if (iBrushStyle != CGraphicsContext::ENullBrush) + { + iPolygonMaskGc->CopySettings(*iMaskGc); + iPolygonMaskGc->CancelClippingRegion(); + + iPolygonMaskGc->SetPenStyle(CGraphicsContext::ESolidPen); + iPolygonMaskGc->SetPenSize(TSize(1,1)); + + User::LeaveIfError(iPolygonMaskGc->DrawPolygon(aPointList,aNumPoints,aFillRule)); + } + } + else + User::LeaveIfError(iMaskGc->DrawPolygon(aPointList,aNumPoints,aFillRule)); + } + +void CFbsBitGcMaskWrapper::Clear() + { + CFbsBitGcWrapper::Clear(); + + // Clear the mask to black. + iMaskGc->SetBrushColor(KRgbBlack); + iMaskGc->Clear(); + + // Reset the brush color to white. + iMaskGc->SetBrushColor(KRgbWhite); + } + +void CFbsBitGcMaskWrapper::SetUnderlineStyle(TFontUnderline aUnderlineStyle) + { + CFbsBitGcWrapper::SetUnderlineStyle(aUnderlineStyle); + iMaskGc->SetUnderlineStyle(aUnderlineStyle); + } + +void CFbsBitGcMaskWrapper::SetStrikethroughStyle(TFontStrikethrough aStrikethroughStyle) + { + CFbsBitGcWrapper::SetStrikethroughStyle(aStrikethroughStyle); + iMaskGc->SetStrikethroughStyle(aStrikethroughStyle); + } + +void CFbsBitGcMaskWrapper::UseFont(const CFbsFont* aFont) + { + CFbsBitGcWrapper::UseFont(aFont); + iMaskGc->UseFont(aFont); + } + +void CFbsBitGcMaskWrapper::SetClippingRegion(const TRegion* aRegion) + { + CFbsBitGcWrapper::SetClippingRegion(aRegion); + iMaskGc->SetClippingRegion(aRegion); + } + +void CFbsBitGcMaskWrapper::SetCharJustification(TInt aExcessWidth, TInt aNumGaps) + { + CFbsBitGcWrapper::SetCharJustification(aExcessWidth, aNumGaps); + iMaskGc->SetCharJustification(aExcessWidth, aNumGaps); + } + +void CFbsBitGcMaskWrapper::SetWordJustification(TInt aExcessWidth, TInt aNumChars) + { + CFbsBitGcWrapper::SetWordJustification(aExcessWidth, aNumChars); + iMaskGc->SetWordJustification(aExcessWidth, aNumChars); + } + +void CFbsBitGcMaskWrapper::DrawLineTo(const TPoint& aPoint) + { + CFbsBitGcWrapper::DrawLineTo(aPoint); + iMaskGc->DrawLineTo(aPoint); + } + +void CFbsBitGcMaskWrapper::MoveTo(const TPoint& aPoint) + { + CFbsBitGcWrapper::MoveTo(aPoint); + iMaskGc->MoveTo(aPoint); + } + +void CFbsBitGcMaskWrapper::DrawPolyLine(const TPoint* aPointList, TInt aNumPoints) + { + CFbsBitGcWrapper::DrawPolyLine(aPointList, aNumPoints); + iMaskGc->DrawPolyLine(aPointList, aNumPoints); + } + +void CFbsBitGcMaskWrapper::DrawEllipse(const TRect& aRect) + { + CFbsBitGcWrapper::DrawEllipse(aRect); + iMaskGc->DrawEllipse(aRect); + } + +void CFbsBitGcMaskWrapper::DrawRect(const TRect& aRect) + { + CFbsBitGcWrapper::DrawRect(aRect); + iMaskGc->DrawRect(aRect); + } + +void CFbsBitGcMaskWrapper::DrawRoundRect(const TRect& aRect, const TSize& aEllipse) + { + CFbsBitGcWrapper::DrawRoundRect(aRect, aEllipse); + iMaskGc->DrawRoundRect(aRect, aEllipse); + } + +void CFbsBitGcMaskWrapper::SetPenStyle(CGraphicsContext::TPenStyle aPenStyle) + { + CFbsBitGcWrapper::SetPenStyle(aPenStyle); + iMaskGc->SetPenStyle(aPenStyle); + } + +void CFbsBitGcMaskWrapper::SetBrushStyle(CGraphicsContext::TBrushStyle aBrushStyle) + { + CFbsBitGcWrapper::SetBrushStyle(aBrushStyle); + iMaskGc->SetBrushStyle(aBrushStyle); + } + +void CFbsBitGcMaskWrapper::SetDrawMode(CGraphicsContext::TDrawMode aDrawMode) + { + CFbsBitGcWrapper::SetDrawMode(aDrawMode); + } + +void CFbsBitGcMaskWrapper::Plot(const TPoint& aPoint) + { + CFbsBitGcWrapper::Plot(aPoint); + iMaskGc->Plot(aPoint); + } + +void CFbsBitGcMaskWrapper::SetPenSize(const TSize& aSize) + { + CFbsBitGcWrapper::SetPenSize(aSize); + iMaskGc->SetPenSize(aSize); + } + +void CFbsBitGcMaskWrapper::DrawArc(const TRect& aRect, const TPoint& aStart, const TPoint& aEnd) + { + CFbsBitGcWrapper::DrawArc(aRect, aStart, aEnd); + iMaskGc->DrawArc(aRect, aStart, aEnd); + } + +void CFbsBitGcMaskWrapper::DrawPie(const TRect& aRect, const TPoint& aStart, const TPoint& aEnd) + { + CFbsBitGcWrapper::DrawPie(aRect, aStart, aEnd); + iMaskGc->DrawPie(aRect, aStart, aEnd); + } + +void CFbsBitGcMaskWrapper::DrawBitmap(const TRect& aDestRect, const CFbsBitmap* aSource, const TRect& aSourceRect) + { + CFbsBitGcWrapper::DrawBitmap(aDestRect, aSource, aSourceRect); + iMaskGc->Clear(aDestRect); + } + +void CFbsBitGcMaskWrapper::DrawText(const TDesC& aText,const TPoint& aPosition) + { + CFbsBitGcWrapper::DrawText(aText, aPosition); + iMaskGc->DrawText(aText, aPosition); + } + + +void CPen::Apply(CFbsBitGcWrapper* aGc) + { + aGc->SetPen(*this); + } + +TInt CPen::Type() const + { + return KWmfGraphicsObjectPen; + } + +void CDummyBrush::Apply(CFbsBitGcWrapper* /* aGc */) + { + } + +TInt CDummyBrush::Type() const + { + return KWmfGraphicsObjectDummyBrush; + } + +void CBrush::Apply(CFbsBitGcWrapper* aGc) + { + aGc->SetBrush(*this); + } + +TInt CBrush::Type() const + { + return KWmfGraphicsObjectBrush; + } + +CPatternBrush* CPatternBrush::NewL() + { + CPatternBrush* self = new(ELeave) CPatternBrush; + + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; + } + +void CPatternBrush::ConstructL() + { + iBitmap = new(ELeave) CFbsBitmap; + } + +CPatternBrush::CPatternBrush() +: iTextColor(KRgbWhite), iBackgroundColor(KRgbWhite) + { + iStyle = CGraphicsContext::EPatternedBrush; + } + +CPatternBrush::~CPatternBrush() + { + delete iBitmap; + delete[] iBitmapBits; + } + +void CPatternBrush::Apply(CFbsBitGcWrapper* aGc) + { + aGc->UseBrushPattern(iBitmap); + CBrush::Apply(aGc); + } + +TInt CPatternBrush::Type() const + { + return KWmfGraphicsObjectPatternBrush; + } + +void CPatternBrush::SetBitmapBits(TUint8* aBitmapBits) + { + iBitmapBits = aBitmapBits; + } + +void CPatternBrush::RealizeBrush(TRgb aTextColor, TRgb aBackgroundColor) + { + if (!iBitmapBits) + return; + + if ((aTextColor == iTextColor) && (aBackgroundColor == iBackgroundColor)) + return; + + iTextColor = aTextColor; + iBackgroundColor = aBackgroundColor; + + TInt width = iBitmap->SizeInPixels().iWidth; + TInt height = iBitmap->SizeInPixels().iHeight; + TInt padding = ((width + 31) & ~31) - width; + TUint pixelMask = 0x80; + TUint8* bytePtr = iBitmapBits; + TBitmapUtil util(iBitmap); + for (TInt y = height - 1; y >= 0; y--) + { + util.Begin(TPoint(0,y)); + + TInt x; + for (x = 0; x < width; x++) + { + TRgb color((bytePtr[0] & pixelMask) ? iBackgroundColor : iTextColor); + util.SetPixel(color.Color64K()); + util.IncXPos(); + + pixelMask >>= 1; + if (pixelMask == 0) + { + pixelMask = 0x80; + bytePtr++; + } + } + + for (x = 0 ; x>= 1; + if (pixelMask == 0) + { + pixelMask = 0x80; + bytePtr++; + } + } + + util.End(); + } + } + +CFbsBitmap* CPatternBrush::Bitmap() + { + return iBitmap; + } + + +CFontObject::CFontObject(CFbsDevice& aDevice,CFbsFont& aFont,TBool aUnderline,TBool aStrikeOut): + iDevice(aDevice), + iFont(aFont), + iUnderline(aUnderline ? EUnderlineOn : EUnderlineOff), + iStrikeOut(aStrikeOut ? EStrikethroughOn : EStrikethroughOff) + {} + +CFontObject::~CFontObject() + { + iDevice.ReleaseFont(&iFont); + } + +void CFontObject::Apply(CFbsBitGcWrapper* aGc) + { + aGc->SetUnderlineStyle(iUnderline); + aGc->SetStrikethroughStyle(iStrikeOut); + aGc->UseFont(&iFont); + } + +TInt CFontObject::Type() const + { + return KWmfGraphicsObjectFont; + } + + +CRectRegion::CRectRegion(CFbsDevice& aDevice, TRegion& aClipRegion, TInt aLeft, TInt aTop, TInt aRight, TInt aBottom): + iRect(aLeft, aTop, aRight, aBottom), iDevice(aDevice), iClipRegion(aClipRegion) + {} + +void CRectRegion::Apply(CFbsBitGcWrapper* aGc) + { + iClipRegion.Clear(); + TRect bitmapRect(iDevice.SizeInPixels()); + iClipRegion.AddRect(bitmapRect); + + TRegionFix<1> rectRegion; + rectRegion.AddRect(iRect); + + iClipRegion.Intersect(rectRegion); + aGc->SetClippingRegion(&iClipRegion); + } + +TInt CRectRegion::Type() const + { + return KWmfGraphicsObjectRegion; + } + + +void CPaletteObject::Apply(CFbsBitGcWrapper* /* aGc */) + { + } + +TInt CPaletteObject::Type() const + { + return KWmfGraphicsObjectPalette; + } + + +// +// CWmfReadCodec +// + +CWmfReadCodec::CWmfReadCodec(TInt aWordsExpected) + : iWordsExpected(aWordsExpected) + { + } + +CWmfReadCodec::~CWmfReadCodec() + { + delete[] iPointArray; + iSavedGcStack.ResetAndDestroy(); + + for (TInt index = 0; index < KWmfMaxGraphicsObjectCount; index++) + delete iGraphicsObject[index]; + + delete iDefaultPen; + delete iDefaultBrush; + delete iGc; + delete iDevice; + delete iMaskDevice; + delete[] iAccumulator; + } + +CWmfReadCodec* CWmfReadCodec::NewL(TInt aWordsExpected) + { + CWmfReadCodec* self = new(ELeave) CWmfReadCodec(aWordsExpected); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; + } + +void CWmfReadCodec::ConstructL() + { + CImageReadCodec::ConstructL(); + + iDefaultPen = new(ELeave) CPen; + iDefaultBrush = new(ELeave) CBrush; + } + +void CWmfReadCodec::InitFrameL(TFrameInfo& aFrameInfo, CFrameImageData& /*aFrameImageData*/, TBool /*aDisableErrorDiffusion*/, CFbsBitmap& aBitmap, CFbsBitmap* aDestinationMask) + { + iWordsProcessed = 0; + + for (TInt index = 0; index < KWmfMaxGraphicsObjectCount; index++) + { + delete iGraphicsObject[index]; + iGraphicsObject[index] = NULL; + } + + delete iGc; iGc = NULL; + delete iDevice; iDevice = NULL; + delete iMaskDevice; iMaskDevice = NULL; + iDevice = CFbsBitmapDevice::NewL(&aBitmap); + + if ((aFrameInfo.iFlags & TFrameInfo::ETransparencyPossible) && aDestinationMask) + { + iMaskDevice = CFbsBitmapDevice::NewL(aDestinationMask); + iGc = CFbsBitGcMaskWrapper::NewL(*iDevice, *iMaskDevice); + } + else + { + iGc = CFbsBitGcWrapper::NewL(*iDevice); + } + + if ((aFrameInfo.iFlags & TFrameInfo::ETransparencyPossible) && !aDestinationMask && aBitmap.DisplayMode() == EColor16MA) + { + // Special case of single 16MA destination bitmap. + const TRgb transparentBlack(0x000000, 0x00); + ClearBitmapL(aBitmap, transparentBlack); + } + else + { + iGc->Clear(); // Ensure bitmap is cleared. (Also clear the mask if we are generating one) + } + + iBkModeOpaque = EFalse; + iMapMode = EMapModeTEXT; + iWindowOrg.SetXY(0,0); + iWindowExt = aBitmap.SizeInPixels(); + iViewportOrg.SetXY(0,0); + iViewportExt = iWindowExt; + + iClipRegion.Clear(); + TRect bitmapRect(iDevice->SizeInPixels()); + iClipRegion.AddRect(bitmapRect); + + iFillRule = CGraphicsContext::EAlternate; + + delete[] iAccumulator; iAccumulator = NULL; + iAccumulatorPtr = NULL; + iAccumulatorSizeInWords = 0; + iLookingForRecord = ETrue; + iRecordSizeInWords = 0; + iFunction = 0; + iWordsToRead = 0; + iFinished = EFalse; + } + +TFrameState CWmfReadCodec::ProcessFrameL(TBufPtr8& aSrc) + { + TUint16* startDataPtr = REINTERPRET_CAST(TUint16*,&aSrc[0]); + TUint16* dataPtr = startDataPtr; + TUint16* dataPtrLimit = dataPtr + Min(TInt(aSrc.Length() / sizeof(TUint16)),iWordsExpected - iWordsProcessed); + + DoProcessL(dataPtr,dataPtrLimit); + + TInt wordsUsed = dataPtr - startDataPtr; + aSrc.Shift(wordsUsed * sizeof(TUint16)); + iWordsProcessed += wordsUsed; + + if (iWordsProcessed >= iWordsExpected || iFinished) + return EFrameComplete; + + return EFrameIncomplete; + } + +void CWmfReadCodec::DoProcessL(TUint16*& aDataPtr,const TUint16* aDataPtrLimit) + { + const TUint16* safeDataPtrLimit = aDataPtrLimit - KWmfMinRecordSizeInWords; + + //Do not spend more than KMaxProcessTime here + TInt systemTickPeriod; + User::LeaveIfError(HAL::Get(HAL::ESystemTickPeriod,systemTickPeriod)); + + TUint currentTick = User::TickCount(); + const TUint tickLimit = currentTick + (KMaxProcessTime / systemTickPeriod); + + //Disable tick check if tickLimit overflow + TBool disableTickCheck = EFalse; + if(tickLimit<=currentTick) + disableTickCheck = ETrue; + + while (aDataPtr <= aDataPtrLimit && (disableTickCheck || currentTick < tickLimit)) + { + if (iLookingForRecord) // Find record + { + if (aDataPtr > safeDataPtrLimit) // Ensures that a record header can always be safely read + return; + + iRecordSizeInWords = (aDataPtr[1] << 16) | aDataPtr[0]; + if (iRecordSizeInWords < KWmfMinRecordSizeInWords || iRecordSizeInWords > iWordsExpected) + User::Leave(KErrCorrupt); + + iFunction = aDataPtr[2]; + + iWordsToRead = iRecordSizeInWords - KWmfMinRecordSizeInWords; + if (iWordsToRead > aDataPtrLimit - aDataPtr - KWmfMinRecordSizeInWords) // Check to see if we need to accumulate data + { + if (iWordsToRead > iAccumulatorSizeInWords) + { + delete[] iAccumulator; + iAccumulator = NULL; + iAccumulatorSizeInWords = 0; + + iAccumulator = new(ELeave) TUint16[iWordsToRead]; + iAccumulatorSizeInWords = iWordsToRead; + } + + iAccumulatorPtr = iAccumulator; + } + else + iAccumulatorPtr = NULL; + + aDataPtr += KWmfMinRecordSizeInWords; + iLookingForRecord = EFalse; + } + else if (iFunction == KWmfTerminateFunction) // Finished + { + iFinished = ETrue; + return; + } + else if (iAccumulatorPtr && iWordsToRead > 0) // Accumulate data + { + const TInt wordsToAccumulate = Min(iWordsToRead,aDataPtrLimit - aDataPtr); + Mem::Copy(iAccumulatorPtr,aDataPtr,wordsToAccumulate * sizeof(TUint16)); + aDataPtr += wordsToAccumulate; + iAccumulatorPtr += wordsToAccumulate; + iWordsToRead -= wordsToAccumulate; + + if (iWordsToRead > 0) + return; + } + else // Process data + { + TUint16* dataPtr = iAccumulatorPtr ? iAccumulator : aDataPtr; + + if (iFunction < 0x0230) + { + if (iFunction < 0x0130) + DoProcess00L(iFunction,dataPtr); + else + DoProcess01L(iFunction,dataPtr); + } + else + { + if (iFunction < 0x500) + DoProcess10L(iFunction,dataPtr); + else + DoProcess11L(iFunction,dataPtr); + } + + if (iAccumulatorPtr) + { + if (iAccumulatorSizeInWords > 0x800) + { + delete[] iAccumulator; + iAccumulator = NULL; + iAccumulatorSizeInWords = 0; + } + + iAccumulatorPtr = NULL; + } + else + aDataPtr += iWordsToRead; + + iLookingForRecord = ETrue; + } + currentTick = User::TickCount(); + } + } + +void CWmfReadCodec::DoProcess00L(TInt aFunction,TUint16* aArgPtr) + { + if (aFunction < 0x0107) + { + if (aFunction < 0x0103) + DoProcess0000L(aFunction,aArgPtr); + else + DoProcess0001L(aFunction,aArgPtr); + } + else + { + if (aFunction < 0x012b) + DoProcess0010L(aFunction,aArgPtr); + else + DoProcess0011L(aFunction,aArgPtr); + } + } + +void CWmfReadCodec::DoProcess01L(TInt aFunction,TUint16* aArgPtr) + { + if (aFunction < 0x020d) + { + if (aFunction < 0x0205) + DoProcess0100L(aFunction,aArgPtr); + else + DoProcess0101L(aFunction,aArgPtr); + } + else + { + if (aFunction < 0x0212) + DoProcess0110L(aFunction,aArgPtr); + else + DoProcess0111L(aFunction,aArgPtr); + } + } + +void CWmfReadCodec::DoProcess10L(TInt aFunction,TUint16* aArgPtr) + { + if (aFunction < 0x0413) + { + if (aFunction < 0x0300) + DoProcess1000L(aFunction,aArgPtr); + else + DoProcess1001L(aFunction,aArgPtr); + } + else + { + if (aFunction < 0x041a) + DoProcess1010L(aFunction,aArgPtr); + else + DoProcess1011L(aFunction,aArgPtr); + } + } + +void CWmfReadCodec::DoProcess11L(TInt aFunction,TUint16* aArgPtr) + { + if (aFunction < 0x0820) + { + if (aFunction < 0x0620) + DoProcess1100L(aFunction,aArgPtr); + else + DoProcess1101L(aFunction,aArgPtr); + } + else + { + if (aFunction < 0x0b00) + DoProcess1110L(aFunction,aArgPtr); + else + DoProcess1111L(aFunction,aArgPtr); + } + } + +void CWmfReadCodec::DoProcess0000L(TInt aFunction,TUint16* aArgPtr) + { + // Not supported: + // 0x0035 - REALIZEPALETTE + // 0x0037 - SETPALENTRIES + // 0x00f7 - CREATEPALETTE + + switch (aFunction) + { + case 0x001e: // SAVEDC + { + CFbsBitGcWrapper* gcCopy = CloneGcL(); + CleanupStack::PushL(gcCopy); + + User::LeaveIfError(iSavedGcStack.Append(gcCopy)); + CleanupStack::Pop(); // gcCopy + } + break; + case 0x00f7: // CREATEPALETTE + AddGraphicsObject(new(ELeave) CPaletteObject); + // Create the object to maintain the handle list + break; + case 0x0102: // SETBKMODE + // 1 = TRANSPARENT, 2 = OPAQUE + iBkModeOpaque = (aArgPtr[0] == 2); + break; + default: + break; + } + } + +void CWmfReadCodec::DoProcess0001L(TInt aFunction,TUint16* aArgPtr) + { + // Not supported: + // 0x0105 - SETRELABS + + switch (aFunction) + { + case 0x0103: // SETMAPMODE + iMapMode = TMapMode(aArgPtr[0]); + break; + case 0x0104: // SETROP2 + SetROP(iGc,aArgPtr[0]); + break; + case 0x0106: // SETPOLYFILLMODE + // 1 = ALTERNATE, 2 = WINDING + iFillRule = (aArgPtr[0] == 2) ? CGraphicsContext::EWinding : CGraphicsContext::EAlternate; + default: + break; + } + } + +void CWmfReadCodec::DoProcess0010L(TInt aFunction,TUint16* aArgPtr) + { + // Not supported: + // 0x0107 - SETSTRETCHBLTMODE + + switch (aFunction) + { + case 0x0108: // SETTEXTCHAREXTRA + { + const TInt extraSpace = LogicalSizeToDeviceSize(aArgPtr[0],ETrue); + if (extraSpace != 0) + { + const TInt numChars = KMaxTInt / extraSpace; // Choose a suitably high number of chars to keep the char spacing going + iGc->SetCharJustification(extraSpace * numChars,numChars); + } + } + break; + case 0x0127: // RESTOREDC + { + const TInt savedGcCount = iSavedGcStack.Count(); + if (savedGcCount > 0) + { + delete iGc; + iGc = iSavedGcStack[savedGcCount - 1]; + iSavedGcStack.Remove(savedGcCount - 1); + ASSERT(iGc); + } + } + break; + case 0x012a: // INVERTREGION + { + CGraphicsObject* object = GraphicsObject(aArgPtr[0]); + if (object && object->Type() == KWmfGraphicsObjectRegion) + { + CRectRegion* rectRgn = STATIC_CAST(CRectRegion*,object); + CFbsBitGcWrapper* gc = CloneGcL(); + + gc->SetPenStyle(CGraphicsContext::ENullPen); + gc->SetBrushStyle(CGraphicsContext::ESolidBrush); + gc->SetBrushColor(KRgbWhite); + gc->SetDrawMode(CGraphicsContext::EDrawModeXOR); + gc->DrawRect(rectRgn->iRect); + + delete gc; + } + } + break; + default: + break; + } + } + +void CWmfReadCodec::DoProcess0011L(TInt aFunction,TUint16* aArgPtr) + { + switch (aFunction) + { + case 0x012e: // SETTEXTALIGN + iTextAlignFlags = aArgPtr[0]; + break; + case 0x012b: // PAINTREGION + { + CGraphicsObject* object = GraphicsObject(aArgPtr[0]); + if (object && object->Type() == KWmfGraphicsObjectRegion) + { + CRectRegion* rectRgn = STATIC_CAST(CRectRegion*,object); + CFbsBitGcWrapper* gc = CloneGcL(); + + gc->SetPenStyle(CGraphicsContext::ENullPen); + gc->DrawRect(rectRgn->iRect); + + delete gc; + } + } + break; + case 0x012c: // SELECTCLIPREGION + case 0x012d: // SELECTOBJECT + { + CGraphicsObject* object = GraphicsObject(aArgPtr[0]); + if (object) + object->Apply(iGc); + } + break; + default: + break; + } + } + +void CWmfReadCodec::DoProcess0100L(TInt aFunction,TUint16* aArgPtr) + { + // Not supported: + // 0x0139 - RESIZEPALETTE + + switch (aFunction) + { + case 0x01f9: // CREATEPATTERNBRUSH + case 0x0142: // DIBCREATEPATTERNBRUSH + { + CPatternBrush* patternBrush = CPatternBrush::NewL(); + + TInt err = ExtractDib(aArgPtr + 2, patternBrush); + if (err == KErrNone) + AddGraphicsObject(patternBrush); + else + { + // Coverity reports a leave_without_push error here because + // CPatternBrush has a CFbsBitmap member which can panic + // during its destructor. The panic has a trapped leave and + // for some reason coverity does not recognise it. + // Mark as false positive + // coverity[leave_without_push : FALSE] + delete patternBrush; + + if (err == KErrNotSupported) // Ignore KErrNotSupported + AddGraphicsObject(new(ELeave) CDummyBrush); // Create the object to maintain the handle list + else + User::Leave(err); + } + } + break; + case 0x01f0: // DELETEOBJECT + RemoveGraphicsObject(aArgPtr[0]); + break; + case 0x0201: // SETBKCOLOR + iGc->SetBackgroundColor(ExtractColor(aArgPtr)); + break; + default: + break; + } + } + +void CWmfReadCodec::DoProcess0101L(TInt aFunction,TUint16* aArgPtr) + { + switch (aFunction) + { + case 0x0209: // SETTEXTCOLOR + iGc->SetTextColor(ExtractColor(aArgPtr)); + break; + case 0x020a: // SETTEXTJUSTIFICATION + iGc->SetWordJustification(LogicalSizeToDeviceSize(aArgPtr[1],ETrue),aArgPtr[0]); + break; + case 0x020b: // SETWINDOWORG + iWindowOrg.SetXY(REINTERPRET_CAST(TInt16*,aArgPtr)[1],REINTERPRET_CAST(TInt16*,aArgPtr)[0]); + break; + case 0x020c: // SETWINDOWEXT + iWindowExt.SetSize(REINTERPRET_CAST(TInt16*,aArgPtr)[1],REINTERPRET_CAST(TInt16*,aArgPtr)[0]); + break; + default: + break; + } + } + +void CWmfReadCodec::DoProcess0110L(TInt aFunction,TUint16* aArgPtr) + { + switch (aFunction) + { + case 0x020d: // SETVIEWPORTORG + if (iIgnoreViewportMetaData == EFalse) + iViewportOrg.SetXY(REINTERPRET_CAST(TInt16*,aArgPtr)[1],REINTERPRET_CAST(TInt16*,aArgPtr)[0]); + break; + case 0x020e: // SETVIEWPORTEXT + if (iIgnoreViewportMetaData == EFalse) + iViewportExt.SetSize(REINTERPRET_CAST(TInt16*,aArgPtr)[1],REINTERPRET_CAST(TInt16*,aArgPtr)[0]); + break; + case 0x020f: // OFFSETWINDOWORG + iWindowOrg += TPoint(REINTERPRET_CAST(TInt16*,aArgPtr)[1],REINTERPRET_CAST(TInt16*,aArgPtr)[0]); + break; + case 0x0211: // OFFSETVIEWPORTORG + if (iIgnoreViewportMetaData == EFalse) + iViewportOrg += TPoint(REINTERPRET_CAST(TInt16*,aArgPtr)[1],REINTERPRET_CAST(TInt16*,aArgPtr)[0]); + break; + default: + break; + } + } + +void CWmfReadCodec::DoProcess0111L(TInt aFunction,TUint16* aArgPtr) + { + // Not supported: + // 0x0220 - OFFSETCLIPRGN + + switch (aFunction) + { + case 0x0213: // LINETO + iGc->DrawLineTo(ExtractPoint(aArgPtr,EFalse)); + break; + case 0x0214: // MOVETO + iGc->MoveTo(ExtractPoint(aArgPtr,EFalse)); + break; + case 0x0228: // FILLREGION + { + CGraphicsObject* regionObject = GraphicsObject(aArgPtr[0]); + CGraphicsObject* brushObject = GraphicsObject(aArgPtr[1]); + if (regionObject && (regionObject->Type() == KWmfGraphicsObjectRegion) + && brushObject && ((brushObject->Type() == KWmfGraphicsObjectBrush) || (brushObject->Type() == KWmfGraphicsObjectPatternBrush))) + { + CRectRegion* rectRgn = STATIC_CAST(CRectRegion*,regionObject); + CFbsBitGcWrapper* gc = CloneGcL(); + + gc->SetPenStyle(CGraphicsContext::ENullPen); + brushObject->Apply(iGc); + gc->DrawRect(rectRgn->iRect); + + delete gc; + } + } + break; + default: + break; + } + } + +void CWmfReadCodec::DoProcess1000L(TInt aFunction,TUint16* aArgPtr) + { + // Not supported: + // 0x0231 - SETMAPPERFLAGS + // 0x0234 - SELECTPALETTE + + switch (aFunction) + { + case 0x02fa: // CREATEPENINDIRECT + { + TInt style = aArgPtr[0]; + + CPen* pen = NULL; + + if (iDefaultPen) + { + pen = iDefaultPen; + iDefaultPen = NULL; + } + else + pen = new(ELeave) CPen; + + switch (style) + { + case 0: // PS_SOLID + pen->iStyle = CGraphicsContext::ESolidPen; + break; + case 1: // PS_DASH + pen->iStyle = CGraphicsContext::EDashedPen; + break; + case 2: // PS_DOT + pen->iStyle = CGraphicsContext::EDottedPen; + break; + case 3: // PS_DASHDOT + pen->iStyle = CGraphicsContext::EDotDashPen; + break; + case 4: // PS_DASHDOTDOT + pen->iStyle = CGraphicsContext::EDotDotDashPen; + break; + case 5: // PS_NULL + pen->iStyle = CGraphicsContext::ENullPen; + break; + case 6: // PS_INSIDEFRAME + case 7: // PS_USERSTYLE + case 8: // PS_ALTERNATE + default: + pen->iStyle = CGraphicsContext::ESolidPen; + break; + } + pen->iSize.iWidth = Max(LogicalSizeToDeviceSize(aArgPtr[1],ETrue),1); + pen->iSize.iHeight = Max(LogicalSizeToDeviceSize(aArgPtr[1],EFalse),1); + pen->iColor = ExtractColor(aArgPtr + 3); + + AddGraphicsObject(pen); + } + break; + case 0x02fb: // CREATEFONTINDIRECT + { + const TInt height = Abs(TInt((TInt16)aArgPtr[0])); + const TInt weight = Abs(TInt(aArgPtr[4])); + const TInt italic = Abs(aArgPtr[5] & 0xff); + const TInt underline = Abs(aArgPtr[5] >> 8); + const TInt strikeOut = Abs(aArgPtr[6] & 0xff); + const TInt pitchAndFamily = Abs(aArgPtr[8] >> 8); + + TFontSpec fontSpec; + fontSpec.iTypeface.SetIsProportional(((pitchAndFamily & 3) != KFontFixedPitch)); + + switch (pitchAndFamily >> 4) + { + case KFontFamilyRoman: + case KFontFamilyScript: + case KFontFamilyDecorative: + fontSpec.iTypeface.SetIsProportional(ETrue); + fontSpec.iTypeface.SetIsSerif(ETrue); + break; + case KFontFamilySwiss: + fontSpec.iTypeface.SetIsProportional(ETrue); + fontSpec.iTypeface.SetIsSerif(EFalse); + break; + case KFontFamilyMono: + fontSpec.iTypeface.SetIsProportional(EFalse); + fontSpec.iTypeface.SetIsSerif(ETrue); + break; + default: + break; + } + + const TInt fontHeight = LogicalSizeToDeviceSize(height,EFalse); + fontSpec.iHeight = Max(fontHeight,1); + + if (weight > KFontNormalWeightLimit) + fontSpec.iFontStyle.SetStrokeWeight(EStrokeWeightBold); + if (italic) + fontSpec.iFontStyle.SetPosture(EPostureItalic); + + CFbsFont* font = NULL; + User::LeaveIfError(iDevice->GetNearestFontInPixels(font,fontSpec)); + + CFontObject* fontObject = new CFontObject(*iDevice,*font,underline,strikeOut); + + if (!fontObject) + { + iDevice->ReleaseFont(font); + User::Leave(KErrNoMemory); + } + else + AddGraphicsObject(fontObject); + } + break; + case 0x02fc: // CREATEBRUSHINDIRECT + { + TInt style = aArgPtr[0]; + TInt hatch = aArgPtr[3]; + + CBrush* brush = NULL; + + if (iDefaultBrush) + { + brush = iDefaultBrush; + iDefaultBrush = NULL; + } + else + brush = new(ELeave) CBrush; + + switch (style) + { + case 0: // BS_SOLID + brush->iStyle = CGraphicsContext::ESolidBrush; + break; + case 1: // BS_NULL, BS_HOLLOW + brush->iStyle = CGraphicsContext::ENullBrush; + break; + case 2: // BS_HATCHED + switch (hatch) + { + case 0: // HS_HORIZONTAL + brush->iStyle = CGraphicsContext::EHorizontalHatchBrush; + break; + case 1: // HS_VERTICAL + brush->iStyle = CGraphicsContext::EVerticalHatchBrush; + break; + case 2: // HS_FDIAGONAL + brush->iStyle = CGraphicsContext::EForwardDiagonalHatchBrush; + break; + case 3: // HS_BDIAGONAL + brush->iStyle = CGraphicsContext::ERearwardDiagonalHatchBrush; + break; + case 4: // HS_CROSS + brush->iStyle = CGraphicsContext::ESquareCrossHatchBrush; + break; + case 5: // HS_DIAGCROSS + brush->iStyle = CGraphicsContext::EDiamondCrossHatchBrush; + break; + default: + brush->iStyle = CGraphicsContext::ESolidBrush; + break; + } + break; + case 3: // BS_PATTERN + case 4: // BS_INDEXED + case 5: // BS_DIBPATTERN + case 6: // BS_DIBPATTERNPT + case 7: // BS_PATTERN8X8 + case 8: // BS_DIBPATTERN8X8 + case 9: // BS_MONOPATTERN + default: + brush->iStyle = CGraphicsContext::ESolidBrush; + break; + } + brush->iColor = ExtractColor(aArgPtr + 1); + + AddGraphicsObject(brush); + } + break; + default: + break; + } + } + +void CWmfReadCodec::DoProcess1001L(TInt aFunction,TUint16* aArgPtr) + { + switch (aFunction) + { + case 0x0324: // POLYGON + case 0x0325: // POLYLINE + { + //check if the record size sufficient for polygon/polyline record. + if(iRecordSizeInWords < KWmfPolyRecordSizeInWords) + { + User::Leave(KErrCorrupt); + } + + const TInt numPoints = aArgPtr[0]; + if (numPoints <= 0) + break; + + //check if the entire data about polygon/polyline is within the record.Each point needs 2 words + if(iRecordSizeInWords < (KWmfPolyRecordSizeInWords + (numPoints * 2))) + { + User::Leave(KErrCorrupt); + } + + if (numPoints > iPointArrayEntries) + { + delete[] iPointArray; + iPointArray = NULL; + iPointArray = new(ELeave) TPoint[numPoints]; + iPointArrayEntries = numPoints; + } + + TUint16* pointPtr = aArgPtr + 1; + TPoint* pointArrayPtr = iPointArray; + + for (TInt count = 0; count < numPoints; count++) + { + *pointArrayPtr++ = ExtractPoint(pointPtr,ETrue); + pointPtr += 2; + } + + if (aFunction == 0x0324) // POLYGON + iGc->DrawPolygonL(iPointArray,numPoints,iFillRule); + else // POLYLINE + iGc->DrawPolyLine(iPointArray, numPoints); + } + break; + case 0x0410: // SCALEWINDOWEXT + { + TInt xMult = aArgPtr[3]; + TInt xDiv = aArgPtr[2]; + TInt yMult = aArgPtr[1]; + TInt yDiv = aArgPtr[0]; + + if (xDiv != 0) + iWindowExt.iWidth = (iWindowExt.iWidth * xMult) / xDiv; + if (yDiv != 0) + iWindowExt.iHeight = (iWindowExt.iHeight * yMult) / yDiv; + } + break; + case 0x0412: // SCALEVIEWPORTEXT + { + if (iIgnoreViewportMetaData == EFalse) + { + TInt xMult = aArgPtr[3]; + TInt xDiv = aArgPtr[2]; + TInt yMult = aArgPtr[1]; + TInt yDiv = aArgPtr[0]; + + if (xDiv != 0) + iViewportExt.iWidth = (iViewportExt.iWidth * xMult) / xDiv; + if (yDiv != 0) + iViewportExt.iHeight = (iViewportExt.iHeight * yMult) / yDiv; + } + } + break; + default: + break; + } + } + +void CWmfReadCodec::DoProcess1010L(TInt aFunction,TUint16* aArgPtr) + { + // Not supported: + // 0x0415 - EXCLUDECLIPRECT + // 0x0419 - FLOODFILL + + switch (aFunction) + { + case 0x0416: // INTERSECTCLIPRECT + { + iIntersectRegion.Clear(); + iIntersectRegion.AddRect(ExtractRect(aArgPtr)); + + iIntersectRegion.Intersect(iClipRegion); + iGc->SetClippingRegion(&iIntersectRegion); + } + break; + case 0x0418: // ELLIPSE + iGc->DrawEllipse(ExtractRect(aArgPtr)); + break; + default: + break; + } + } + +void CWmfReadCodec::DoProcess1011L(TInt aFunction,TUint16* aArgPtr) + { + // Not supported: + // 0x0436 - ANIMATEPALETTE + + switch (aFunction) + { + case 0x041b: // RECTANGLE + iGc->DrawRect(ExtractRect(aArgPtr)); + break; + case 0x041f: // SETPIXEL + { + CFbsBitGcWrapper* gc = CloneGcL(); + + gc->SetPenColor(ExtractColor(aArgPtr)); + gc->Plot(ExtractPoint(aArgPtr + 2,EFalse)); + + delete gc; + } + break; + case 0x0429: // FRAMEREGION + { + CGraphicsObject* object1 = GraphicsObject(aArgPtr[0]); + CGraphicsObject* object2 = GraphicsObject(aArgPtr[1]); + + if (object1 && object1->Type() == KWmfGraphicsObjectRegion && + object2 && ((object2->Type() == KWmfGraphicsObjectBrush) || (object2->Type() == KWmfGraphicsObjectPatternBrush))) + { + CRectRegion* region = STATIC_CAST(CRectRegion*,object1); + CBrush* brush = STATIC_CAST(CBrush*,object2); + + if (brush->iStyle == CGraphicsContext::ESolidBrush) + { + CFbsBitGcWrapper* gc = CloneGcL(); + + gc->SetPenStyle(CGraphicsContext::ESolidPen); + gc->SetPenColor(brush->iColor); + gc->SetPenSize(TSize(aArgPtr[3],aArgPtr[2])); + gc->SetBrushStyle(CGraphicsContext::ENullBrush); + + gc->DrawRect(region->iRect); + + delete gc; + } + } + } + break; + default: + break; + } + } + +void CWmfReadCodec::DoProcess1100L(TInt aFunction,TUint16* aArgPtr) + { + // Not supported: + // 0x0548 - EXTFLOODFILL + + switch (aFunction) + { + case 0x0521: // TEXTOUT + { + CFbsBitGcWrapper* gc = CloneGcL(); + CleanupStack::PushL(gc); + + gc->SetPenStyle(CGraphicsContext::ESolidPen); + gc->SetTextPenColor(); + if (iBkModeOpaque) + gc->SetBrushStyle(CGraphicsContext::ESolidBrush); + else + gc->SetBrushStyle(CGraphicsContext::ENullBrush); + + if(iRecordSizeInWords < KMinTextoutRecordSizeInWords) + { + // Invalid Textout record. + User::Leave(KErrCorrupt); + } + //read the count of text-string bytes. The text is padded if necessary. + //The count doesn't include the padded byte. + const TInt count = *aArgPtr++; + //convert into words + TUint stringWords = (count+1) / 2; + if ((KMinTextoutRecordSizeInWords + stringWords) > iRecordSizeInWords) + { + // Invalid Textout record. + User::Leave(KErrCorrupt); + } + const TPtrC8 text((TUint8*)aArgPtr,count); + + DrawTextL(text, ExtractPoint(aArgPtr + stringWords, EFalse), gc); + + CleanupStack::PopAndDestroy(gc); + } + break; + case 0x0538: // POLYPOLYGON + { + //check if the record size sufficient for polygon/polyline record. + if(iRecordSizeInWords < KWmfPolyRecordSizeInWords) + { + User::Leave(KErrCorrupt); + } + const TInt numPolygons = *aArgPtr++; + if (numPolygons <= 0) + break; + + //check if the words that contain the number of points for each polygon are within the record + if(iRecordSizeInWords < (KWmfPolyRecordSizeInWords + numPolygons)) + { + User::Leave(KErrCorrupt); + } + + //index of word that has point for polygons + TInt pointWord = KWmfPolyRecordSizeInWords + numPolygons; + TUint16* pointArgs = aArgPtr + numPolygons; + for (TInt polygonIndex = 0; polygonIndex < numPolygons; polygonIndex++) + { + const TInt numPoints = aArgPtr[polygonIndex]; + if (numPoints <= 0) + break; + + //check if the point values are available within the record; each point needs 2 words + pointWord += numPoints * 2; + if(iRecordSizeInWords < pointWord ) + { + User::Leave(KErrCorrupt); + } + + if (numPoints > iPointArrayEntries) + { + delete[] iPointArray; + iPointArray = NULL; + iPointArray = new(ELeave) TPoint[numPoints]; + iPointArrayEntries = numPoints; + } + + TPoint* pointArrayPtr = iPointArray; + for (TInt pointIndex = 0; pointIndex < numPoints; pointIndex++) + { + *pointArrayPtr++ = ExtractPoint(pointArgs,ETrue); + pointArgs += 2; + } + + iGc->DrawPolygonL(iPointArray,numPoints,iFillRule); + } + } + break; + case 0x061c: // ROUNDRECT + iGc->DrawRoundRect(ExtractRect(aArgPtr + 2),ExtractPoint(aArgPtr,EFalse).AsSize()); + break; + case 0x061d: // PATBLT + { + TInt left = LogicalCoordToDeviceCoord(aArgPtr[5],ETrue); + TInt top = LogicalCoordToDeviceCoord(aArgPtr[4],EFalse); + TInt width = LogicalSizeToDeviceSize(aArgPtr[3],ETrue); + TInt height = LogicalSizeToDeviceSize(aArgPtr[2],EFalse); + + CFbsBitGcWrapper* gc = CloneGcL(); + + gc->SetPenStyle(CGraphicsContext::ENullPen); + SetROP3(gc, aArgPtr[0] | (aArgPtr[1] << 16)); + gc->DrawRect(TRect(TPoint(left,top),TSize(width,height))); + + delete gc; + } + break; + default: + break; + } + } + +void CWmfReadCodec::DoProcess1101L(TInt aFunction,TUint16* aArgPtr) + { + // Not supported: + // 0x0626 - ESCAPE + + switch (aFunction) + { + case 0x06ff: // CREATEREGION + { + TInt left = LogicalCoordToDeviceCoord(aArgPtr[7],ETrue); + TInt top = LogicalCoordToDeviceCoord(aArgPtr[8],EFalse); + TInt right = LogicalCoordToDeviceCoord(aArgPtr[9],ETrue); + TInt bottom = LogicalCoordToDeviceCoord(aArgPtr[10],EFalse); + + AddGraphicsObject(new(ELeave) CRectRegion(*iDevice, iClipRegion, left, top, right, bottom)); + } + break; + case 0x0817: // ARC + iGc->DrawArc(ExtractRect(aArgPtr + 4),ExtractPoint(aArgPtr + 2,EFalse),ExtractPoint(aArgPtr,EFalse)); + break; + case 0x081a: // PIE + iGc->DrawPie(ExtractRect(aArgPtr + 4),ExtractPoint(aArgPtr + 2,EFalse),ExtractPoint(aArgPtr,EFalse)); + break; + default: + break; + } + } + +void CWmfReadCodec::DoProcess1110L(TInt aFunction,TUint16* aArgPtr) + { + // Not supported: + // 0x0830 - CHORD + // 0x0922 - BITBLT + // 0x0940 - DIBBITBLT + + switch (aFunction) + { + case 0x0a32: // EXTTEXTOUT + { + CFbsBitGcWrapper* gc = CloneGcL(); + CleanupStack::PushL(gc); + + gc->SetPenStyle(CGraphicsContext::ESolidPen); + gc->SetTextPenColor(); + if (iBkModeOpaque) + gc->SetBrushStyle(CGraphicsContext::ESolidBrush); + else + gc->SetBrushStyle(CGraphicsContext::ENullBrush); + + const TPoint pos(ExtractPoint(aArgPtr,EFalse)); + const TInt count = aArgPtr[2]; + const TInt flag = aArgPtr[3]; + + aArgPtr += (flag & KExtTextOutFlagClipped) ? 8 : 4; + + const TPtrC8 text((TUint8*)aArgPtr,count); + + DrawTextL(text,pos,gc); + + CleanupStack::PopAndDestroy(gc); + } + break; + default: + break; + } + } + +void CWmfReadCodec::DoProcess1111L(TInt aFunction,TUint16* aArgPtr) + { + // Not supported: + // 0x0b23 - STRETCHBLT + // 0x0d33 - SETDIBTODEV + + switch (aFunction) + { + case 0x0b41: // DIBSTRETCHBLT + { + const TInt16* argPtr = (TInt16*)aArgPtr; + const TInt srcX = argPtr[5]; + const TInt srcY = argPtr[4]; + const TInt srcWidth = argPtr[3]; + const TInt srcHeight = argPtr[2]; + const TInt dstX = LogicalCoordToDeviceCoord(argPtr[9],ETrue); + const TInt dstY = LogicalCoordToDeviceCoord(argPtr[8],EFalse); + const TInt dstWidth = LogicalSizeToDeviceSize(argPtr[7],ETrue); + const TInt dstHeight = LogicalSizeToDeviceSize(argPtr[6],EFalse); + + CFbsBitmap* dib = new(ELeave) CFbsBitmap; + TInt err = ExtractDib(aArgPtr + 10, dib); + + CleanupStack::PushL(dib); + if (err == KErrNone) + { + const TRect srcRect(TPoint(srcX,srcY),TSize(srcWidth,srcHeight)); + const TRect dstRect(TPoint(dstX,dstY),TSize(dstWidth,dstHeight)); + + iGc->DrawBitmap(dstRect,dib,srcRect); + } + else if (err != KErrNotSupported) // Ignore KErrNotSupported + User::Leave(err); + + CleanupStack::PopAndDestroy(dib); + } + break; + case 0x0f43: // STRETCHDIB + { + const TInt16* argPtr = (TInt16*)aArgPtr; + const TInt srcX = argPtr[6]; + const TInt srcY = argPtr[5]; + const TInt srcWidth = argPtr[4]; + const TInt srcHeight = argPtr[3]; + const TInt dstX = LogicalCoordToDeviceCoord(argPtr[10],ETrue); + const TInt dstY = LogicalCoordToDeviceCoord(argPtr[9],EFalse); + const TInt dstWidth = LogicalSizeToDeviceSize(argPtr[8],ETrue); + const TInt dstHeight = LogicalSizeToDeviceSize(argPtr[7],EFalse); + + CFbsBitmap* dib = new(ELeave) CFbsBitmap; + TInt err = ExtractDib(aArgPtr + 11, dib); + + CleanupStack::PushL(dib); + if (err == KErrNone) + { + const TRect srcRect(TPoint(srcX,srcY),TSize(srcWidth,srcHeight)); + const TRect dstRect(TPoint(dstX,dstY),TSize(dstWidth,dstHeight)); + + iGc->DrawBitmap(dstRect,dib,srcRect); + } + else if (err != KErrNotSupported) // Ignore KErrNotSupported + User::Leave(err); + + CleanupStack::PopAndDestroy(dib); + } + break; + default: + break; + } + } + +void CWmfReadCodec::DrawTextL(const TDesC8& aText, const TPoint& aPos, CFbsBitGcWrapper* aGc) + { + if(aText.Length()==0) + return; + + HBufC* unicodeText = HBufC::NewMaxLC(aText.Length()); + TPtr16 text = unicodeText->Des(); + text.Copy(aText); + + TPoint pos(aPos); + const CFbsFont* font = iGc->CurrentFont(); + + if (font) + { + const TInt textAlignHorz = iTextAlignFlags & KTextAlignMaskHorz; + const TInt textAlignVert = iTextAlignFlags & KTextAlignMaskVert; + + switch (textAlignHorz) + { + case KTextAlignFlagRight: + pos.iX -= font->TextWidthInPixels(text); + break; + case KTextAlignFlagCenter: + pos.iX -= font->TextWidthInPixels(text) / 2; + break; + default: // KTextAlignFlagLeft + break; + } + + // rather than use font->AscentInPixels(), font->DescentInPixels(), + // which don't include the height of accents etc, + // use the maximum possible ascent/decent instead + TInt ascent; + TInt descent; + TOpenFontMetrics fontMetrics; + if (font->IsOpenFont() && font->GetFontMetrics(fontMetrics)) + { + ascent = fontMetrics.MaxHeight(); + descent = fontMetrics.MaxDepth(); + } + else + { + ascent = font->AscentInPixels(); + descent = font->DescentInPixels(); + } + + switch (textAlignVert) + { + case KTextAlignFlagBottom: + pos.iY -= descent; + break; + case KTextAlignFlagBaseline: + break; + default: // KTextAlignFlagTop + pos.iY += ascent; + break; + } + aGc->DrawText(*unicodeText,pos); + } + + CleanupStack::PopAndDestroy(unicodeText); + } + +void CWmfReadCodec::AddGraphicsObject(CGraphicsObject* aObject) + { + for (TInt index = 0; index < KWmfMaxGraphicsObjectCount; index++) + { + if (iGraphicsObject[index] == NULL) + { + iGraphicsObject[index] = aObject; + return; + } + } + + delete aObject; // No more space so throw the object away + } + +CGraphicsObject* CWmfReadCodec::GraphicsObject(TInt aHandle) + { + if (aHandle < KWmfMaxGraphicsObjectCount) + return iGraphicsObject[aHandle]; + + return NULL; + } + +void CWmfReadCodec::RemoveGraphicsObject(TInt aHandle) + { + if (aHandle < KWmfMaxGraphicsObjectCount) + { + CGraphicsObject* object = iGraphicsObject[aHandle]; + + if (object) + { + if (object->Type() == KWmfGraphicsObjectPen && !iDefaultPen) + iDefaultPen = STATIC_CAST(CPen*,object); + else if (object->Type() == KWmfGraphicsObjectBrush && !iDefaultBrush) + iDefaultBrush = STATIC_CAST(CBrush*,object); + else + delete object; + + iGraphicsObject[aHandle] = NULL; + } + } + } + +CFbsBitGcWrapper* CWmfReadCodec::CloneGcL() + { + CFbsBitGcWrapper* gcCopy; + if (iMaskDevice) + gcCopy = CFbsBitGcMaskWrapper::NewL(*iDevice, *iMaskDevice, static_cast (iGc)); + else + gcCopy = CFbsBitGcWrapper::NewL(*iDevice, iGc); + + return gcCopy; + } + +TInt CWmfReadCodec::LogicalCoordToDeviceCoord(TInt aLogicalCoord,TBool aHorizontal) + { + if (aHorizontal) + { + if (iWindowExt.iWidth != 0) + return ((aLogicalCoord - iWindowOrg.iX) * iViewportExt.iWidth / iWindowExt.iWidth) + iViewportOrg.iX; + } + else + { + if (iWindowExt.iHeight != 0) + return ((aLogicalCoord - iWindowOrg.iY) * iViewportExt.iHeight / iWindowExt.iHeight) + iViewportOrg.iY; + } + + return 0; + } + +TInt CWmfReadCodec::LogicalSizeToDeviceSize(TInt aLogicalSize,TBool aHorizontal) + { + if (aHorizontal) + { + if (iWindowExt.iWidth != 0) + return aLogicalSize * iViewportExt.iWidth / iWindowExt.iWidth; + } + else + { + if (iWindowExt.iHeight != 0) + return aLogicalSize * iViewportExt.iHeight / iWindowExt.iHeight; + } + + return 0; + } + +void CWmfReadCodec::SetROP(CFbsBitGcWrapper* aGc,TInt aROP) + { + CGraphicsContext::TDrawMode drawMode = CGraphicsContext::EDrawModePEN; + + switch (aROP) + { + case 1: // R2_BLACK + aGc->SetPenColor(KRgbBlack); + aGc->SetBrushColor(KRgbBlack); + aGc->SetDrawMode(drawMode); + return; + + case 11: // R2_NOP + aGc->SetPenStyle(CGraphicsContext::ENullPen); + aGc->SetBrushStyle(CGraphicsContext::ENullBrush); + aGc->SetDrawMode(drawMode); + return; + + case 16: // R2_WHITE + aGc->SetPenColor(KRgbWhite); + aGc->SetBrushColor(KRgbWhite); + aGc->SetDrawMode(drawMode); + return; + + default: + break; + } + + switch (aROP) + { + case 2: drawMode = CGraphicsContext::EDrawModeNOTANDNOT; break; // R2_NOTMERGEPEN + case 3: drawMode = CGraphicsContext::EDrawModeANDNOT; break; // R2_MASKNOTPEN + case 4: drawMode = CGraphicsContext::EDrawModeNOTPEN; break; // R2_NOTCOPYPEN + case 5: drawMode = CGraphicsContext::EDrawModeNOTAND; break; // R2_MASKPENNOT + case 6: drawMode = CGraphicsContext::EDrawModeNOTSCREEN; break; // R2_NOT + case 7: drawMode = CGraphicsContext::EDrawModeXOR; break; // R2_XORPEN + case 8: drawMode = CGraphicsContext::EDrawModeNOTORNOT; break; // R2_NOTMASKPEN + case 9: drawMode = CGraphicsContext::EDrawModeAND; break; // R2_MASKPEN + case 10: drawMode = CGraphicsContext::EDrawModeNOTXOR; break; // R2_NOTXORPEN + + case 12: break; // R2_MERGENOTPEN (not supported) + case 13: break; // R2_COPYPEN + case 14: drawMode = CGraphicsContext::EDrawModeNOTOR; break; // R2_MERGEPENNOT + case 15: drawMode = CGraphicsContext::EDrawModeOR; break; // R2_MERGEPEN + + default: + break; + } + + aGc->RestorePenAndBrush(); + aGc->SetDrawMode(drawMode); + } + +void CWmfReadCodec::SetROP3(CFbsBitGcWrapper* aGc,TInt aROP) + { + CGraphicsContext::TDrawMode drawMode = CGraphicsContext::EDrawModePEN; + switch (aROP) + { + case 0x005A0049: // PATINVERT + drawMode = CGraphicsContext::EDrawModeXOR; + break; + case 0x00550009: // DSTINVERT + drawMode = CGraphicsContext::EDrawModeNOTSCREEN; + aGc->SetBrushStyle(CGraphicsContext::ESolidBrush); + break; + case 0x00000042: // BLACKNESS + aGc->SetBrushColor(KRgbBlack); + aGc->SetBrushStyle(CGraphicsContext::ESolidBrush); + break; + case 0x00FF0062: // WHITENESS + aGc->SetBrushColor(KRgbWhite); + aGc->SetBrushStyle(CGraphicsContext::ESolidBrush); + break; + + case 0x00F00021: // PATCOPY + default: + break; + } + + aGc->SetDrawMode(drawMode); + } + +TRgb CWmfReadCodec::ExtractColor(const TUint16* aArgPtr) + { + return TRgb(aArgPtr[0] & 0xff,aArgPtr[0] >> 8,aArgPtr[1] & 0xff); + } + +TPoint CWmfReadCodec::ExtractPoint(const TUint16* aArgPtr,TBool aXYOrder) + { + TInt16* coordPtr = (TInt16*)aArgPtr; + + TInt left = coordPtr[0]; + TInt top = coordPtr[1]; + + if (!aXYOrder) + { + TInt temp = left; + left = top; + top = temp; + } + + left = LogicalCoordToDeviceCoord(left,ETrue); + top = LogicalCoordToDeviceCoord(top,EFalse); + + return TPoint(left,top); + } + +TRect CWmfReadCodec::ExtractRect(const TUint16* aArgPtr) + { + TInt16* coordPtr = (TInt16*)aArgPtr; + + TInt left = LogicalCoordToDeviceCoord(coordPtr[3],ETrue); + TInt top = LogicalCoordToDeviceCoord(coordPtr[2],EFalse); + TInt right = LogicalCoordToDeviceCoord(coordPtr[1],ETrue); + TInt bottom = LogicalCoordToDeviceCoord(coordPtr[0],EFalse); + + return TRect(left,top,right,bottom); + } + +TInt CWmfReadCodec::ExtractDib(const TUint16* aArgPtr, CPatternBrush* aPatternBrush) + { + TInt bitCount = aArgPtr[7]; + if (bitCount != 1) + return ExtractDib(aArgPtr, aPatternBrush->Bitmap()); + + TInt structSize = aArgPtr[0] | (aArgPtr[1] << 16); + TInt width = aArgPtr[2] | (aArgPtr[3] << 16); + TInt height = aArgPtr[4] | (aArgPtr[5] << 16); + + // Skip biPlanes half-word + TInt compression = aArgPtr[8] | (aArgPtr[9] << 16); + if (compression) + return KErrNotSupported; + + // Skip biSizeImage word + TInt xPixelsPerMeter = aArgPtr[12] | (aArgPtr[13] << 16); + TInt yPixelsPerMeter = aArgPtr[14] | (aArgPtr[15] << 16); + + // Skip biClrUsed word + // Skip biClrImportant word + + TUint8* bytePtr = (TUint8*)aArgPtr; + bytePtr += structSize; + + CFbsBitmap* bitmap = aPatternBrush->Bitmap(); + TInt err = bitmap->Create(TSize(width,height), EColor64K); + if (err != KErrNone) + return err; + + TSize twipsSize(0,0); + if (xPixelsPerMeter > 0) + twipsSize.iWidth = KTwipsPerCm * 100 * width / xPixelsPerMeter; + if (yPixelsPerMeter > 0) + twipsSize.iHeight = KTwipsPerCm * 100 * height / yPixelsPerMeter; + bitmap->SetSizeInTwips(twipsSize); + + // Skip the palette. + bytePtr+= 8; + + // Set the pattern bits. + TInt padding = ((width + 31) & ~31) - width; + TInt byteTotal = ((width+padding)*height)/8; + TUint8* bitmapBits = new TUint8[byteTotal]; + if (!bitmapBits) + return KErrNoMemory; + + Mem::Copy(bitmapBits, bytePtr, byteTotal); + aPatternBrush->SetBitmapBits(bitmapBits); + return KErrNone; + } + +TInt CWmfReadCodec::ExtractDib(const TUint16* aArgPtr, CFbsBitmap* aBitmap) + { + const TInt structSize = aArgPtr[0] | (aArgPtr[1] << 16); + const TInt width = aArgPtr[2] | (aArgPtr[3] << 16); + const TInt height = aArgPtr[4] | (aArgPtr[5] << 16); + + // Skip biPlanes half-word + const TInt bitCount = aArgPtr[7]; + const TInt compression = aArgPtr[8] | (aArgPtr[9] << 16); + if (((bitCount != 24) && (bitCount != 8) && (bitCount != 1)) || compression) + return KErrNotSupported; + + // Skip biSizeImage word + const TInt xPixelsPerMeter = aArgPtr[12] | (aArgPtr[13] << 16); + const TInt yPixelsPerMeter = aArgPtr[14] | (aArgPtr[15] << 16); + + // Skip biClrUsed word + // Skip biClrImportant word + + TUint8* bytePtr = (TUint8*)aArgPtr; + bytePtr += structSize; + + TInt err = aBitmap->Create(TSize(width,height), EColor64K); + if (err != KErrNone) + return err; + + TSize twipsSize(0,0); + if (xPixelsPerMeter > 0) + twipsSize.iWidth = KTwipsPerCm * 100 * width / xPixelsPerMeter; + if (yPixelsPerMeter > 0) + twipsSize.iHeight = KTwipsPerCm * 100 * height / yPixelsPerMeter; + aBitmap->SetSizeInTwips(twipsSize); + + TBitmapUtil util(aBitmap); + if (bitCount == 24) + { + TInt byteWidth = 3*width; + TInt padding = ((byteWidth + 3) & ~3) - byteWidth; + for (TInt y = height - 1; y >= 0; y--) + { + util.Begin(TPoint(0,y)); + for (TInt x = 0; x < width; x++) + { + TRgb color(bytePtr[2],bytePtr[1],bytePtr[0]); + util.SetPixel(color.Color64K()); + util.IncXPos(); + bytePtr += 3; + } + bytePtr += padding; + util.End(); + } + } + else if (bitCount == 8) + { + // Read the palette. + TRgb* palette = new TRgb[256]; + if (!palette) + return KErrNoMemory; + + for (TInt count = 0; count < 256; count++) + { + TInt blue = bytePtr[0]; + TInt green = bytePtr[1]; + TInt red = bytePtr[2]; + + bytePtr += 4; // Skip rgbReserved + palette[count] = TRgb(red, green, blue); + } + + const TInt padding = ((width + 3) & ~3) - width; + for (TInt y = height - 1; y >= 0; y--) + { + util.Begin(TPoint(0,y)); + for (TInt x = 0; x < width; x++) + { + TRgb color(palette[bytePtr[0]]); + util.SetPixel(color.Color64K()); + util.IncXPos(); + bytePtr++; + } + bytePtr += padding; + util.End(); + } + + delete[] palette; + } + else // 1bpp + { + // Read the palette. + TRgb palette[2]; + for (TInt count = 0; count < 2; count++) + { + TInt blue = bytePtr[0]; + TInt green = bytePtr[1]; + TInt red = bytePtr[2]; + + bytePtr += 4; // Skip rgbReserved + palette[count] = TRgb(red, green, blue); + } + + const TInt padding = ((width + 31) & ~31) - width; + TUint pixelMask = 0x80; + for (TInt y = height - 1; y >= 0; y--) + { + util.Begin(TPoint(0,y)); + + TInt x; + for (x = 0; x < width; x++) + { + TRgb color(palette[(bytePtr[0] & pixelMask) ? 1 : 0]); + util.SetPixel(color.Color64K()); + util.IncXPos(); + + pixelMask >>= 1; + if (pixelMask == 0) + { + pixelMask = 0x80; + bytePtr++; + } + } + + for (x = 0 ; x>= 1; + if (pixelMask == 0) + { + pixelMask = 0x80; + bytePtr++; + } + } + + util.End(); + } + } + + return KErrNone; + } + +TInt CWmfReadCodec::ReducedSize(const TSize& aOriginalSize,TInt aReductionFactor, TSize& aReducedSize) const + { + aReducedSize = aOriginalSize; + if (aReductionFactor<0) + { + return KErrArgument; + } + TInt roundup = aReductionFactor>0? 1<<(aReductionFactor-1): 0; + aReducedSize.SetSize(((aOriginalSize.iWidth+roundup)>>aReductionFactor), + ((aOriginalSize.iHeight+roundup)>>aReductionFactor) ); + return KErrNone; + } + +TInt CWmfReadCodec::ReductionFactor(const TSize& aOriginalSize, const TSize& aReducedSize) const + { + if( (aReducedSize.iWidth<=0) || (aReducedSize.iHeight<=0)) + { + return 0; + } + TInt reductionFactor = 0; + TInt roundup=0; + while( ((aOriginalSize.iWidth+roundup)>>reductionFactor) > aReducedSize.iWidth || + ((aOriginalSize.iHeight+roundup)>>reductionFactor) > aReducedSize.iHeight) + { + reductionFactor++; + roundup=1<<(reductionFactor-1); + } + return reductionFactor; + } + +void CWmfReadCodec::SetIgnoreViewportMetaData(TBool aIgnoreViewportMetaData) + { + iIgnoreViewportMetaData = aIgnoreViewportMetaData; + }