From ed5640d8b587fbcfed7dd7967f3de04b37a76f26 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 11:06:44 +0200 Subject: Adding upstream version 4:7.4.7. Signed-off-by: Daniel Baumann --- vcl/source/filter/ipict/ipict.cxx | 2041 +++++++++++++++++++++++++++++++++++++ vcl/source/filter/ipict/shape.cxx | 259 +++++ vcl/source/filter/ipict/shape.hxx | 57 ++ 3 files changed, 2357 insertions(+) create mode 100644 vcl/source/filter/ipict/ipict.cxx create mode 100644 vcl/source/filter/ipict/shape.cxx create mode 100644 vcl/source/filter/ipict/shape.hxx (limited to 'vcl/source/filter/ipict') diff --git a/vcl/source/filter/ipict/ipict.cxx b/vcl/source/filter/ipict/ipict.cxx new file mode 100644 index 000000000..0f8fd5ba0 --- /dev/null +++ b/vcl/source/filter/ipict/ipict.cxx @@ -0,0 +1,2041 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "shape.hxx" +#include + +#include + // complete FilterConfigItem for GraphicImport under -fsanitize=function + +namespace PictReaderInternal { + namespace { + + //! utilitary class to store a pattern, ... + class Pattern { + public: + //! constructor + Pattern() : penStyle(PEN_SOLID), + brushStyle(BRUSH_SOLID), + nBitCount(64), + isColor(false), + isRead(false) + {} + + //! reads black/white pattern from SvStream + sal_uInt8 read(SvStream &stream); + //! sets the color + void setColor(Color col) { isColor = true; color = col; } + /** returns a color which can be "used" to replace the pattern, + * created from ForeColor and BackColor, ... + * + * note: maybe, we must also use some mode PatCopy, ... to define the color + */ + Color getColor(Color bkColor, Color fgColor) const { + if (isColor) return color; + // we create a gray pattern from nBitCount + double alpha = nBitCount / 64.0; + return Color(sal_uInt8(alpha*fgColor.GetRed()+(1.0-alpha)*bkColor.GetRed()), + sal_uInt8(alpha*fgColor.GetGreen()+(1.0-alpha)*bkColor.GetGreen()), + sal_uInt8(alpha*fgColor.GetBlue()+(1.0-alpha)*bkColor.GetBlue())); + } + + //! returns true if this is the default pattern + bool isDefault() const { return !isRead; } + + enum PenStyle { PEN_NULL, PEN_SOLID, PEN_DOT, PEN_DASH, PEN_DASHDOT }; + enum BrushStyle { BRUSH_SOLID, BRUSH_HORZ, BRUSH_VERT, + BRUSH_CROSS, BRUSH_DIAGCROSS, BRUSH_UPDIAG, BRUSH_DOWNDIAG, + BRUSH_25, BRUSH_50, BRUSH_75 }; + // Data + enum PenStyle penStyle; + enum BrushStyle brushStyle; + short nBitCount; + + bool isColor; // true if it is a color pattern + Color color; + + protected: + // flag to know if the pattern came from reading the picture, or if it is the default pattern + bool isRead; + }; + + } + + sal_uInt8 Pattern::read(SvStream &stream) { + unsigned char nbyte[8] = {0}; + isColor = false; + + // count the no of bits in pattern which are set to 1: + nBitCount=0; + for (unsigned char & ny : nbyte) { + stream.ReadChar( reinterpret_cast(ny) ); + for (short nx=0; nx<8; nx++) { + if ( (ny & (1<(nbyte[0])<<8)| + static_cast(nbyte[1]))<<8)| + static_cast(nbyte[2]))<<8)| + static_cast(nbyte[3]); + sal_uInt32 nLoBytes = (((((static_cast(nbyte[4])<<8)| + static_cast(nbyte[5]))<<8)| + static_cast(nbyte[6]))<<8)| + static_cast(nbyte[7]); + + // create a PenStyle: + if (nBitCount<=0) penStyle=PEN_NULL; + else if (nBitCount<=16) penStyle=PEN_DOT; + else if (nBitCount<=32) penStyle=PEN_DASHDOT; + else if (nBitCount<=48) penStyle=PEN_DASH; + else penStyle=PEN_SOLID; + + // create a BrushStyle: + if (nHiBytes==0xffffffff && nLoBytes==0xffffffff) brushStyle=BRUSH_SOLID; + else if (nHiBytes==0xff000000 && nLoBytes==0x00000000) brushStyle=BRUSH_HORZ; + else if (nHiBytes==0x80808080 && nLoBytes==0x80808080) brushStyle=BRUSH_VERT; + else if (nHiBytes==0xff808080 && nLoBytes==0x80808080) brushStyle=BRUSH_CROSS; + else if (nHiBytes==0x01824428 && nLoBytes==0x10284482) brushStyle=BRUSH_DIAGCROSS; + else if (nHiBytes==0x80402010 && nLoBytes==0x08040201) brushStyle=BRUSH_UPDIAG; + else if (nHiBytes==0x01020408 && nLoBytes==0x10204080) brushStyle=BRUSH_DOWNDIAG; + else if (nBitCount<=24) brushStyle=BRUSH_25; + else if (nBitCount<=40) brushStyle=BRUSH_50; + else if (nBitCount<=56) brushStyle=BRUSH_75; + else brushStyle=BRUSH_SOLID; + + isRead = true; + + return 8; + } +} + +//============================ PictReader ================================== + +namespace { + +enum class PictDrawingMethod { + FRAME, PAINT, ERASE, INVERT, FILL, + TEXT, UNDEFINED +}; + +class PictReader { + typedef class PictReaderInternal::Pattern Pattern; +private: + + SvStream * pPict; // The Pict file to read. + VclPtr pVirDev; // Here the drawing method will be called. + // A recording into the GDIMetaFile will take place. + + sal_uInt64 nOrigPos; // Initial position in pPict. + bool IsVersion2; // If it is a version 2 Pictfile. + tools::Rectangle aBoundingRect; // Min/Max-Rectangle for the whole drawing. + + Point aPenPosition; + Point aTextPosition; + Color aActForeColor; + Color aActBackColor; + Pattern eActPenPattern; + Pattern eActFillPattern; + Pattern eActBackPattern; + Size nActPenSize; + // Note: Postscript mode is stored by setting eActRop to RasterOp::N1 + RasterOp eActROP; + PictDrawingMethod eActMethod; + Size aActOvalSize; + vcl::Font aActFont; + + Fraction aHRes; + Fraction aVRes; + + Point ReadPoint(); + + Point ReadDeltaH(Point aBase); + Point ReadDeltaV(Point aBase); + + Point ReadUnsignedDeltaH(Point aBase); + Point ReadUnsignedDeltaV(Point aBase); + + Size ReadSize(); + + Color ReadColor(); + + Color ReadRGBColor(); + + void ReadRectangle(tools::Rectangle & rRect); + + sal_uInt64 ReadPolygon(tools::Polygon & rPoly); + + sal_uInt64 ReadPixPattern(Pattern &pattern); + + tools::Rectangle aLastRect; + sal_uInt8 ReadAndDrawRect(PictDrawingMethod eMethod); + sal_uInt8 ReadAndDrawSameRect(PictDrawingMethod eMethod); + + tools::Rectangle aLastRoundRect; + sal_uInt8 ReadAndDrawRoundRect(PictDrawingMethod eMethod); + sal_uInt8 ReadAndDrawSameRoundRect(PictDrawingMethod eMethod); + + tools::Rectangle aLastOval; + sal_uInt8 ReadAndDrawOval(PictDrawingMethod eMethod); + sal_uInt8 ReadAndDrawSameOval(PictDrawingMethod eMethod); + + tools::Polygon aLastPolygon; + sal_uInt64 ReadAndDrawPolygon(PictDrawingMethod eMethod); + sal_uInt8 ReadAndDrawSamePolygon(PictDrawingMethod eMethod); + + tools::Rectangle aLastArcRect; + sal_uInt8 ReadAndDrawArc(PictDrawingMethod eMethod); + sal_uInt8 ReadAndDrawSameArc(PictDrawingMethod eMethod); + + sal_uInt64 ReadAndDrawRgn(PictDrawingMethod eMethod); + sal_uInt8 ReadAndDrawSameRgn(PictDrawingMethod eMethod); + + // returns true if there's no need to print the shape/text/frame + bool IsInvisible( PictDrawingMethod eMethod ) const { + if ( eActROP == RasterOp::N1 ) return true; + if ( eMethod == PictDrawingMethod::FRAME && nActPenSize.IsEmpty() ) return true; + return false; + } + + void DrawingMethod(PictDrawingMethod eMethod); + + sal_uInt64 ReadAndDrawText(); + + sal_uInt64 ReadPixMapEtc(BitmapEx & rBitmap, bool bBaseAddr, bool bColorTable, + tools::Rectangle * pSrcRect, tools::Rectangle * pDestRect, + bool bMode, bool bMaskRgn); + + void ReadHeader(); + // Reads the header of the Pict file, set IsVersion and aBoundingRect + + sal_uInt64 ReadData(sal_uInt16 nOpcode); + // Reads the date of anOopcode and executes the operation. + // The number of data bytes belonging to the opcode will be returned + // in any case. + + void SetLineColor( const Color& rColor ); + void SetFillColor( const Color& rColor ); + + // OSNOLA: returns the text encoding which must be used for system id + static rtl_TextEncoding GetTextEncoding (sal_uInt16 fId = 0xFFFF); + +public: + + PictReader() + : pPict(nullptr) + , pVirDev(nullptr) + , nOrigPos(0) + , IsVersion2(false) + , eActROP(RasterOp::OverPaint) + , eActMethod(PictDrawingMethod::UNDEFINED) + { + aActFont.SetCharSet(GetTextEncoding()); + } + + void ReadPict( SvStream & rStreamPict, GDIMetaFile & rGDIMetaFile ); + // reads a pict file from the stream and fills the GDIMetaFile + +}; + +} + +static void SetByte(sal_uInt16& nx, sal_uInt16 ny, vcl::bitmap::RawBitmap& rBitmap, sal_uInt16 nPixelSize, sal_uInt8 nDat, sal_uInt16 nWidth, std::vector const & rvPalette) +{ + switch (nPixelSize) + { + case 1: + rBitmap.SetPixel(ny, nx++, rvPalette[(nDat >> 7) & 1]); + if ( nx == nWidth ) break; + rBitmap.SetPixel(ny, nx++, rvPalette[(nDat >> 6) & 1]); + if ( nx == nWidth ) break; + rBitmap.SetPixel(ny, nx++, rvPalette[(nDat >> 5) & 1]); + if ( nx == nWidth ) break; + rBitmap.SetPixel(ny, nx++, rvPalette[(nDat >> 4) & 1]); + if ( nx == nWidth ) break; + rBitmap.SetPixel(ny, nx++, rvPalette[(nDat >> 3) & 1]); + if ( nx == nWidth ) break; + rBitmap.SetPixel(ny, nx++, rvPalette[(nDat >> 2) & 1]); + if ( nx == nWidth ) break; + rBitmap.SetPixel(ny, nx++, rvPalette[(nDat >> 1) & 1]); + if ( nx == nWidth ) break; + rBitmap.SetPixel(ny, nx++, rvPalette[nDat & 1]); + break; + case 2: + rBitmap.SetPixel(ny, nx++, rvPalette[nDat >> 6]); + if ( nx == nWidth ) break; + rBitmap.SetPixel(ny, nx++, rvPalette[(nDat>>4)&3]); + if ( nx == nWidth ) break; + rBitmap.SetPixel(ny, nx++, rvPalette[(nDat>>2)&3]); + if ( nx == nWidth ) break; + rBitmap.SetPixel(ny, nx++, rvPalette[nDat & 3]); + break; + case 4: + rBitmap.SetPixel(ny, nx++, rvPalette[nDat >> 4]); + if ( nx == nWidth ) break; + rBitmap.SetPixel(ny, nx++, rvPalette[nDat & 0x0f]); + break; + case 8: + rBitmap.SetPixel(ny, nx++, rvPalette[nDat]); + break; + } +} + +//=================== methods of PictReader ============================== +rtl_TextEncoding PictReader::GetTextEncoding (sal_uInt16 fId) { + static rtl_TextEncoding enc = []() + { + rtl_TextEncoding def = osl_getThreadTextEncoding(); + // we keep osl_getThreadTextEncoding only if it is a mac encoding + switch(def) { + case RTL_TEXTENCODING_APPLE_ROMAN: + case RTL_TEXTENCODING_APPLE_ARABIC: + case RTL_TEXTENCODING_APPLE_CENTEURO: + case RTL_TEXTENCODING_APPLE_CROATIAN: + case RTL_TEXTENCODING_APPLE_CYRILLIC: + case RTL_TEXTENCODING_APPLE_DEVANAGARI: + case RTL_TEXTENCODING_APPLE_FARSI: + case RTL_TEXTENCODING_APPLE_GREEK: + case RTL_TEXTENCODING_APPLE_GUJARATI: + case RTL_TEXTENCODING_APPLE_GURMUKHI: + case RTL_TEXTENCODING_APPLE_HEBREW: + case RTL_TEXTENCODING_APPLE_ICELAND: + case RTL_TEXTENCODING_APPLE_ROMANIAN: + case RTL_TEXTENCODING_APPLE_THAI: + case RTL_TEXTENCODING_APPLE_TURKISH: + case RTL_TEXTENCODING_APPLE_UKRAINIAN: + case RTL_TEXTENCODING_APPLE_CHINSIMP: + case RTL_TEXTENCODING_APPLE_CHINTRAD: + case RTL_TEXTENCODING_APPLE_JAPANESE: + case RTL_TEXTENCODING_APPLE_KOREAN: + return def; break; + default: + break; + } + return RTL_TEXTENCODING_APPLE_ROMAN; + }(); + if (fId == 13) return RTL_TEXTENCODING_ADOBE_DINGBATS; // CHECKME + if (fId == 23) return RTL_TEXTENCODING_ADOBE_SYMBOL; + return enc; +} + +void PictReader::SetLineColor( const Color& rColor ) +{ + pVirDev->SetLineColor( rColor ); +} + +void PictReader::SetFillColor( const Color& rColor ) +{ + pVirDev->SetFillColor( rColor ); +} + +Point PictReader::ReadPoint() +{ + short nx(0), ny(0); + + pPict->ReadInt16( ny ).ReadInt16( nx ); + + Point aPoint(nx - aBoundingRect.Left(), ny - aBoundingRect.Top()); + + SAL_INFO("filter.pict", "ReadPoint: " << aPoint); + return aPoint; +} + +Point PictReader::ReadDeltaH(Point aBase) +{ + signed char ndh(0); + + pPict->ReadChar( reinterpret_cast(ndh) ); + + return Point( aBase.X() + static_cast(ndh), aBase.Y() ); +} + +Point PictReader::ReadDeltaV(Point aBase) +{ + signed char ndv(0); + + pPict->ReadChar( reinterpret_cast(ndv) ); + + return Point( aBase.X(), aBase.Y() + static_cast(ndv) ); +} + +Point PictReader::ReadUnsignedDeltaH(Point aBase) +{ + sal_uInt8 ndh(0); + + pPict->ReadUChar( ndh ); + + return Point( aBase.X() + static_cast(ndh), aBase.Y() ); +} + +Point PictReader::ReadUnsignedDeltaV(Point aBase) +{ + sal_uInt8 ndv(0); + + pPict->ReadUChar( ndv ); + + return Point( aBase.X(), aBase.Y() + static_cast(ndv) ); +} + +Size PictReader::ReadSize() +{ + short nx(0), ny(0); + + pPict->ReadInt16( ny ).ReadInt16( nx ); + + return Size(nx, ny); +} + +Color PictReader::ReadColor() +{ + Color aCol; + + sal_uInt32 nCol(0); + pPict->ReadUInt32( nCol ); + switch (nCol) + { + case 33: aCol=COL_BLACK; break; + case 30: aCol=COL_WHITE; break; + case 205: aCol=COL_LIGHTRED; break; + case 341: aCol=COL_LIGHTGREEN; break; + case 409: aCol=COL_LIGHTBLUE; break; + case 273: aCol=COL_LIGHTCYAN; break; + case 137: aCol=COL_LIGHTMAGENTA; break; + case 69: aCol=COL_YELLOW; break; + default: aCol=COL_LIGHTGRAY; + } + return aCol; +} + +Color PictReader::ReadRGBColor() +{ + sal_uInt16 nR(0), nG(0), nB(0); + + pPict->ReadUInt16( nR ).ReadUInt16( nG ).ReadUInt16( nB ); + return Color( static_cast( nR >> 8 ), static_cast( nG >> 8 ), static_cast( nB >> 8 ) ); +} + +void PictReader::ReadRectangle(tools::Rectangle & rRect) +{ + Point aTopLeft = ReadPoint(); + Point aBottomRight = ReadPoint(); + if (!pPict->good() || aTopLeft.X() > aBottomRight.X() || aTopLeft.Y() > aBottomRight.Y()) + { + SAL_WARN("filter.pict", "broken rectangle"); + pPict->SetError( SVSTREAM_FILEFORMAT_ERROR ); + rRect = tools::Rectangle(); + return; + } + rRect=tools::Rectangle(aTopLeft,aBottomRight); + + SAL_INFO("filter.pict", "ReadRectangle: " << rRect); +} + +sal_uInt64 PictReader::ReadPolygon(tools::Polygon & rPoly) +{ + sal_uInt16 nSize(0); + pPict->ReadUInt16(nSize); + pPict->SeekRel(8); + sal_uInt64 nDataSize = static_cast(nSize); + nSize=(nSize-10)/4; + const size_t nMaxPossiblePoints = pPict->remainingSize() / 2 * sizeof(sal_uInt16); + if (nSize > nMaxPossiblePoints) + { + SAL_WARN("filter.pict", "pict record claims to have: " << nSize << " points, but only " << nMaxPossiblePoints << " possible, clamping"); + nSize = nMaxPossiblePoints; + } + rPoly.SetSize(nSize); + for (sal_uInt16 i = 0; i < nSize; ++i) + { + rPoly.SetPoint(ReadPoint(), i); + if (!pPict->good()) + { + rPoly.SetSize(i); + break; + } + } + return nDataSize; +} + +sal_uInt64 PictReader::ReadPixPattern(PictReader::Pattern &pattern) +{ + // Don't know if this is correct because no picture which contains PixPatterns found. + // Here again the attempt to calculate the size of the date to create simple StarView-Styles + // from them. Luckily a PixPattern always contains a normal pattern. + + sal_uInt64 nDataSize; + + sal_uInt16 nPatType(0); + pPict->ReadUInt16(nPatType); + if (nPatType==1) { + pattern.read(*pPict); + BitmapEx aBMP; + nDataSize=ReadPixMapEtc(aBMP,false,true,nullptr,nullptr,false,false); + // CHANGEME: use average pixmap colors to update the pattern, ... + if (nDataSize!=0xffffffff) nDataSize+=10; + } + else if (nPatType==2) { + pattern.read(*pPict); + // RGBColor + sal_uInt16 nR, nG, nB; + pPict->ReadUInt16( nR ).ReadUInt16( nG ).ReadUInt16( nB ); + Color col(static_cast( nR >> 8 ), static_cast( nG >> 8 ), static_cast( nB >> 8 ) ); + pattern.setColor(col); + nDataSize=16; + } + else nDataSize=0xffffffff; + + return nDataSize; +} + +sal_uInt8 PictReader::ReadAndDrawRect(PictDrawingMethod eMethod) +{ + ReadRectangle(aLastRect); + ReadAndDrawSameRect(eMethod); + return 8; +} + +sal_uInt8 PictReader::ReadAndDrawSameRect(PictDrawingMethod eMethod) +{ + if (IsInvisible(eMethod)) return 0; + DrawingMethod(eMethod); + PictReaderShape::drawRectangle( pVirDev, eMethod == PictDrawingMethod::FRAME, aLastRect, nActPenSize ); + return 0; +} + +sal_uInt8 PictReader::ReadAndDrawRoundRect(PictDrawingMethod eMethod) +{ + ReadRectangle(aLastRoundRect); + ReadAndDrawSameRoundRect(eMethod); + return 8; +} + +sal_uInt8 PictReader::ReadAndDrawSameRoundRect(PictDrawingMethod eMethod) +{ + if (IsInvisible(eMethod)) return 0; + DrawingMethod(eMethod); + PictReaderShape::drawRoundRectangle( pVirDev, eMethod == PictDrawingMethod::FRAME, aLastRoundRect, aActOvalSize, nActPenSize ); + return 0; +} + +sal_uInt8 PictReader::ReadAndDrawOval(PictDrawingMethod eMethod) +{ + ReadRectangle(aLastOval); + ReadAndDrawSameOval(eMethod); + return 8; +} + +sal_uInt8 PictReader::ReadAndDrawSameOval(PictDrawingMethod eMethod) +{ + if (IsInvisible(eMethod)) return 0; + DrawingMethod(eMethod); + PictReaderShape::drawEllipse( pVirDev, eMethod == PictDrawingMethod::FRAME, aLastOval, nActPenSize ); + return 0; +} + +sal_uInt64 PictReader::ReadAndDrawPolygon(PictDrawingMethod eMethod) +{ + sal_uInt64 nDataSize; + nDataSize=ReadPolygon(aLastPolygon); + ReadAndDrawSamePolygon(eMethod); + return nDataSize; +} + +sal_uInt8 PictReader::ReadAndDrawSamePolygon(PictDrawingMethod eMethod) +{ + if (IsInvisible(eMethod)) return 0; + DrawingMethod(eMethod); + PictReaderShape::drawPolygon( pVirDev, eMethod == PictDrawingMethod::FRAME, aLastPolygon, nActPenSize ); + return 0; +} + + +sal_uInt8 PictReader::ReadAndDrawArc(PictDrawingMethod eMethod) +{ + ReadRectangle(aLastArcRect); + ReadAndDrawSameArc(eMethod); + return 12; +} + +sal_uInt8 PictReader::ReadAndDrawSameArc(PictDrawingMethod eMethod) +{ + short nstartAngle, narcAngle; + + pPict->ReadInt16( nstartAngle ).ReadInt16( narcAngle ); + if (!pPict->good() || IsInvisible(eMethod)) return 4; + DrawingMethod(eMethod); + + if (narcAngle<0) { + nstartAngle = nstartAngle + narcAngle; + narcAngle=-narcAngle; + } + const double pi = 2 * acos(0.0); + double fAng1 = static_cast(nstartAngle) * pi / 180.0; + double fAng2 = static_cast(nstartAngle + narcAngle) * pi / 180.0; + PictReaderShape::drawArc( pVirDev, eMethod == PictDrawingMethod::FRAME, aLastArcRect, fAng1, fAng2, nActPenSize ); + return 4; +} + +sal_uInt64 PictReader::ReadAndDrawRgn(PictDrawingMethod eMethod) +{ + sal_uInt16 nSize(0); + pPict->ReadUInt16( nSize ); + + // read the DATA + // + // a region data is a mask and is probably coded as + // - the first 8 bytes: bdbox ( which can be read by ReadRectangle ) + // - then a list of line modifiers: y_i, a_0, b_0, a_1, b_1, ..., a_{n_i}, b_{n_i}, 0x7fff + // - 0x7fff + // where y_i is the increasing sequences of line coordinates + // and on each line: a0 < b0 < a1 < b1 < ... < a_{n_i} < b_{n_i} + + // it can be probably decoded as : + // M=an empty mask: ie. (0, 0, ... ) with (left_box-right_box+1) zeroes + // then for each line (y_i): + // - takes M and inverts all values in [a_0,b_0-1], in [a_1,b_1-1] ... + // - sets M = new y_i line mask + ReadAndDrawSameRgn(eMethod); + return static_cast(nSize); +} + +sal_uInt8 PictReader::ReadAndDrawSameRgn(PictDrawingMethod eMethod) +{ + if (IsInvisible(eMethod)) return 0; + DrawingMethod(eMethod); + // DISPLAY: ...???... + return 0; +} + +void PictReader::DrawingMethod(PictDrawingMethod eMethod) +{ + if( eActMethod==eMethod ) return; + switch (eMethod) { + case PictDrawingMethod::FRAME: + if (eActPenPattern.isDefault()) + SetLineColor( aActForeColor ); + else + SetLineColor(eActPenPattern.getColor(aActBackColor, aActForeColor)); + SetFillColor( COL_TRANSPARENT ); + pVirDev->SetRasterOp(eActROP); + break; + case PictDrawingMethod::PAINT: + SetLineColor( COL_TRANSPARENT ); + if (eActPenPattern.isDefault()) + SetFillColor( aActForeColor ); + else + SetFillColor(eActPenPattern.getColor(aActBackColor, aActForeColor)); + pVirDev->SetRasterOp(eActROP); + break; + case PictDrawingMethod::ERASE: + SetLineColor( COL_TRANSPARENT ); + if (eActBackPattern.isDefault()) + SetFillColor( aActBackColor );// Osnola: previously aActForeColor + else // checkMe + SetFillColor(eActBackPattern.getColor(COL_BLACK, aActBackColor)); + pVirDev->SetRasterOp(RasterOp::OverPaint); + break; + case PictDrawingMethod::INVERT: // checkme + SetLineColor( COL_TRANSPARENT); + SetFillColor( COL_BLACK ); + pVirDev->SetRasterOp(RasterOp::Invert); + break; + case PictDrawingMethod::FILL: + SetLineColor( COL_TRANSPARENT ); + if (eActFillPattern.isDefault()) + SetFillColor( aActForeColor ); + else + SetFillColor(eActFillPattern.getColor(aActBackColor, aActForeColor)); + pVirDev->SetRasterOp(RasterOp::OverPaint); + break; + case PictDrawingMethod::TEXT: + aActFont.SetColor(aActForeColor); + aActFont.SetFillColor(aActBackColor); + aActFont.SetTransparent(true); + pVirDev->SetFont(aActFont); + pVirDev->SetRasterOp(RasterOp::OverPaint); + break; + default: + break; // -Wall undefined not handled... + } + eActMethod=eMethod; +} + +sal_uInt64 PictReader::ReadAndDrawText() +{ + char sText[256]; + + char nByteLen(0); + pPict->ReadChar(nByteLen); + sal_uInt32 nLen = static_cast(nByteLen)&0x000000ff; + sal_uInt32 nDataLen = nLen + 1; + nLen = pPict->ReadBytes(&sText, nLen); + + if (IsInvisible( PictDrawingMethod::TEXT )) return nDataLen; + DrawingMethod( PictDrawingMethod::TEXT ); + + // remove annoying control characters: + while ( nLen > 0 && static_cast(sText[ nLen - 1 ]) < 32 ) + nLen--; + sText[ nLen ] = 0; + OUString aString( sText, strlen(sText), aActFont.GetCharSet()); + pVirDev->DrawText( Point( aTextPosition.X(), aTextPosition.Y() ), aString ); + return nDataLen; +} + +sal_uInt64 PictReader::ReadPixMapEtc( BitmapEx &rBitmap, bool bBaseAddr, bool bColorTable, tools::Rectangle* pSrcRect, + tools::Rectangle* pDestRect, bool bMode, bool bMaskRgn ) +{ + std::unique_ptr pBitmap; + sal_uInt16 nPackType(0), nPixelSize(0), nCmpCount(0), nCmpSize(0); + sal_uInt8 nDat(0), nRed(0), nGreen(0), nBlue(0); + + // The calculation of nDataSize is considering the size of the whole data. + size_t nDataSize = 0; + + // conditionally skip BaseAddr + if ( bBaseAddr ) + { + pPict->SeekRel( 4 ); + nDataSize += 4; + } + + // Read PixMap or Bitmap structure; + sal_uInt16 nRowBytes(0), nBndX(0), nBndY(0), nWidth(0), nHeight(0); + pPict->ReadUInt16(nRowBytes).ReadUInt16(nBndY).ReadUInt16(nBndX).ReadUInt16(nHeight).ReadUInt16(nWidth); + if (nBndY > nHeight) + return 0xffffffff; + nHeight = nHeight - nBndY; + if (nHeight == 0) + return 0xffffffff; + if (nBndX > nWidth) + return 0xffffffff; + nWidth = nWidth - nBndX; + if (nWidth == 0) + return 0xffffffff; + + std::vector aPalette; + const bool bNotMonoChrome = (nRowBytes & 0x8000) != 0; + if (bNotMonoChrome) + { // it is a PixMap + nRowBytes &= 0x3fff; + sal_uInt16 nVersion; + sal_uInt32 nPackSize; + sal_uInt16 nPixelType; + sal_uInt32 nPlaneBytes; + sal_uInt32 nHRes, nVRes; + pPict->ReadUInt16( nVersion ).ReadUInt16( nPackType ).ReadUInt32( nPackSize ).ReadUInt32( nHRes ).ReadUInt32( nVRes ).ReadUInt16( nPixelType ).ReadUInt16( nPixelSize ).ReadUInt16( nCmpCount ).ReadUInt16( nCmpSize ).ReadUInt32( nPlaneBytes ); + + pPict->SeekRel( 8 ); + nDataSize += 46; + + if ( bColorTable ) + { + pPict->SeekRel( 6 ); + sal_uInt16 nColTabSize(0); + pPict->ReadUInt16(nColTabSize); + + if (nColTabSize > 255) + return 0xffffffff; + + ++nColTabSize; + + aPalette.resize(nColTabSize); + + for (size_t i = 0; i < nColTabSize; ++i) + { + pPict->SeekRel(2); + sal_uInt8 nDummy; + pPict->ReadUChar( nRed ).ReadUChar( nDummy ).ReadUChar( nGreen ).ReadUChar( nDummy ).ReadUChar( nBlue ).ReadUChar( nDummy ); + aPalette[i] = Color(nRed, nGreen, nBlue); + } + + nDataSize += 8 + nColTabSize * 8; + } + } + else + { + nRowBytes &= 0x3fff; + nPixelSize = nCmpCount = nCmpSize = 1; + nDataSize += 10; + aPalette.resize(2); + aPalette[0] = Color(0xff, 0xff, 0xff); + aPalette[1] = Color(0, 0, 0); + } + + // conditionally read source rectangle: + if ( pSrcRect != nullptr) + { + sal_uInt16 nTop, nLeft, nBottom, nRight; + pPict->ReadUInt16( nTop ).ReadUInt16( nLeft ).ReadUInt16( nBottom ).ReadUInt16( nRight ); + *pSrcRect = tools::Rectangle(nLeft, nTop, nRight, nBottom); + nDataSize += 8; + } + + // conditionally read destination rectangle: + if ( pDestRect != nullptr ) + { + Point aTL = ReadPoint(); + Point aBR = ReadPoint(); + *pDestRect = tools::Rectangle( aTL, aBR ); + nDataSize += 8; + } + + // conditionally read mode (or skip it): + if ( bMode ) + { + pPict->SeekRel(2); + nDataSize += 2; + } + + // conditionally read region (or skip it): + if ( bMaskRgn ) + { + sal_uInt16 nSize(0); + pPict->ReadUInt16( nSize ); + pPict->SeekRel( nSize - 2 ); + nDataSize += nSize; + } + + // read and write Bitmap bits: + if ( nPixelSize == 1 || nPixelSize == 2 || nPixelSize == 4 || nPixelSize == 8 ) + { + sal_uInt16 nSrcBPL, nDestBPL; + size_t nCount; + + if ( nPixelSize == 1 ) nSrcBPL = ( nWidth + 7 ) >> 3; + else if ( nPixelSize == 2 ) nSrcBPL = ( nWidth + 3 ) >> 2; + else if ( nPixelSize == 4 ) nSrcBPL = ( nWidth + 1 ) >> 1; + else nSrcBPL = nWidth; + nDestBPL = ( nSrcBPL + 3 ) & 0xfffc; + if (!nRowBytes || nRowBytes < nSrcBPL || nRowBytes > nDestBPL) + return 0xffffffff; + + if (nRowBytes < 8 || nPackType == 1) + { + if (nHeight > pPict->remainingSize() / (sizeof(sal_uInt8) * nRowBytes)) + return 0xffffffff; + } + else + { + size_t nByteCountSize = nRowBytes > 250 ? sizeof(sal_uInt16) : sizeof(sal_uInt8); + if (nHeight > pPict->remainingSize() / nByteCountSize) + return 0xffffffff; + } + + pBitmap.reset(new vcl::bitmap::RawBitmap( Size(nWidth, nHeight), 24 )); + + for (sal_uInt16 ny = 0; ny < nHeight; ++ny) + { + sal_uInt16 nx = 0; + if ( nRowBytes < 8 || nPackType == 1 ) + { + for (size_t i = 0; i < nRowBytes; ++i) + { + pPict->ReadUChar( nDat ); + if ( nx < nWidth ) + SetByte(nx, ny, *pBitmap, nPixelSize, nDat, nWidth, aPalette); + } + nDataSize += nRowBytes; + } + else + { + sal_uInt16 nByteCount(0); + if ( nRowBytes > 250 ) + { + pPict->ReadUInt16( nByteCount ); + nDataSize += 2 + static_cast(nByteCount); + } + else + { + sal_uInt8 nByteCountAsByte(0); + pPict->ReadUChar( nByteCountAsByte ); + nByteCount = static_cast(nByteCountAsByte) & 0x00ff; + nDataSize += 1 + nByteCount; + } + + while (pPict->good() && nByteCount) + { + sal_uInt8 nFlagCounterByte(0); + pPict->ReadUChar(nFlagCounterByte); + if ( ( nFlagCounterByte & 0x80 ) == 0 ) + { + nCount = static_cast(nFlagCounterByte) + 1; + for (size_t i = 0; i < nCount; ++i) + { + pPict->ReadUChar( nDat ); + if ( nx < nWidth ) + SetByte(nx, ny, *pBitmap, nPixelSize, nDat, nWidth, aPalette); + } + nByteCount -= 1 + nCount; + } + else + { + nCount = static_cast( 1 - sal_Int16( static_cast(nFlagCounterByte) | 0xff00 ) ); + pPict->ReadUChar( nDat ); + for (size_t i = 0; i < nCount; ++i) + { + if ( nx < nWidth ) + SetByte(nx, ny, *pBitmap, nPixelSize, nDat, nWidth, aPalette); + } + nByteCount -= 2; + } + } + } + } + } + else if ( nPixelSize == 16 ) + { + sal_uInt8 nByteCountAsByte, nFlagCounterByte; + sal_uInt16 nByteCount, nCount, nD; + sal_uInt64 nSrcBitsPos; + + if (nWidth > nRowBytes / 2) + return 0xffffffff; + + if (nRowBytes < 8 || nPackType == 1) + { + if (nHeight > pPict->remainingSize() / (sizeof(sal_uInt8) * nRowBytes)) + return 0xffffffff; + } + else + { + size_t nByteCountSize = nRowBytes > 250 ? sizeof(sal_uInt16) : sizeof(sal_uInt8); + if (nHeight > pPict->remainingSize() / nByteCountSize) + return 0xffffffff; + } + + pBitmap.reset(new vcl::bitmap::RawBitmap( Size(nWidth, nHeight), 24 )); + + for (sal_uInt16 ny = 0; ny < nHeight; ++ny) + { + sal_uInt16 nx = 0; + if ( nRowBytes < 8 || nPackType == 1 ) + { + for (size_t i = 0; i < nWidth; ++i) + { + pPict->ReadUInt16( nD ); + nRed = static_cast( nD >> 7 ); + nGreen = static_cast( nD >> 2 ); + nBlue = static_cast( nD << 3 ); + pBitmap->SetPixel(ny, nx++, Color(nRed, nGreen, nBlue)); + } + nDataSize += static_cast(nWidth) * 2; + } + else + { + nSrcBitsPos = pPict->Tell(); + if ( nRowBytes > 250 ) + { + pPict->ReadUInt16( nByteCount ); + nByteCount += 2; + } + else + { + pPict->ReadUChar( nByteCountAsByte ); + nByteCount = static_cast(nByteCountAsByte) & 0x00ff; + nByteCount++; + } + while ( nx != nWidth ) + { + pPict->ReadUChar( nFlagCounterByte ); + if ( (nFlagCounterByte & 0x80) == 0) + { + nCount=static_cast(nFlagCounterByte)+1; + if ( nCount + nx > nWidth) + nCount = nWidth - nx; + if (pPict->remainingSize() < sizeof(sal_uInt16) * nCount) + return 0xffffffff; + /* SJ: the RLE decoding seems not to be correct here, + I don't want to change this until I have a bugdoc for + this case. Have a look at 32bit, there I changed the + encoding, so that it is used a straight forward array + */ + for (size_t i = 0; i < nCount; ++i) + { + pPict->ReadUInt16( nD ); + nRed = static_cast( nD >> 7 ); + nGreen = static_cast( nD >> 2 ); + nBlue = static_cast( nD << 3 ); + pBitmap->SetPixel(ny, nx++, Color(nRed, nGreen, nBlue)); + } + } + else + { + if (pPict->remainingSize() < sizeof(sal_uInt16)) + return 0xffffffff; + nCount=(1-sal_Int16(static_cast(nFlagCounterByte)|0xff00)); + if ( nCount + nx > nWidth ) + nCount = nWidth - nx; + pPict->ReadUInt16( nD ); + nRed = static_cast( nD >> 7 ); + nGreen = static_cast( nD >> 2 ); + nBlue = static_cast( nD << 3 ); + for (size_t i = 0; i < nCount; ++i) + { + pBitmap->SetPixel(ny, nx++, Color(nRed, nGreen, nBlue)); + } + } + } + nDataSize += nByteCount; + pPict->Seek(nSrcBitsPos+nByteCount); + } + } + } + else if ( nPixelSize == 32 ) + { + sal_uInt16 nByteCount; + size_t nCount; + sal_uInt64 nSrcBitsPos; + if ( nRowBytes != 4*nWidth ) + return 0xffffffff; + + if ( nRowBytes < 8 || nPackType == 1 ) + { + const size_t nMaxPixels = pPict->remainingSize() / 4; + const size_t nMaxRows = nMaxPixels / nWidth; + if (nHeight > nMaxRows) + return 0xffffffff; + const size_t nMaxCols = nMaxPixels / nHeight; + if (nWidth > nMaxCols) + return 0xffffffff; + + pBitmap.reset(new vcl::bitmap::RawBitmap( Size(nWidth, nHeight), 24 )); + + for (sal_uInt16 ny = 0; ny < nHeight; ++ny) + { + for (sal_uInt16 nx = 0; nx < nWidth; ++nx) + { + sal_uInt8 nDummy; + pPict->ReadUChar( nDummy ).ReadUChar( nRed ).ReadUChar( nGreen ).ReadUChar( nBlue ); + pBitmap->SetPixel(ny, nx, Color(nRed, nGreen, nBlue)); + } + nDataSize += static_cast(nWidth) * 4; + } + } + else if ( nPackType == 2 ) + { + const size_t nMaxPixels = pPict->remainingSize() / 3; + const size_t nMaxRows = nMaxPixels / nWidth; + if (nHeight > nMaxRows) + return 0xffffffff; + const size_t nMaxCols = nMaxPixels / nHeight; + if (nWidth > nMaxCols) + return 0xffffffff; + + pBitmap.reset(new vcl::bitmap::RawBitmap( Size(nWidth, nHeight), 24 )); + + for (sal_uInt16 ny = 0; ny < nHeight; ++ny) + { + for (sal_uInt16 nx = 0; nx < nWidth; ++nx) + { + pPict->ReadUChar( nRed ).ReadUChar( nGreen ).ReadUChar( nBlue ); + pBitmap->SetPixel(ny, nx, Color(nRed, nGreen, nBlue)); + } + nDataSize += static_cast(nWidth) * 3; + } + } + else + { + sal_uInt8 nByteCountAsByte; + sal_uInt8 nFlagCounterByte; + if ( ( nCmpCount == 3 ) || ( nCmpCount == 4 ) ) + { + size_t nByteCountSize = nRowBytes > 250 ? sizeof(sal_uInt16) : sizeof(sal_uInt8); + if (nHeight > pPict->remainingSize() / nByteCountSize) + return 0xffffffff; + + pBitmap.reset(new vcl::bitmap::RawBitmap( Size(nWidth, nHeight), 24 )); + + // cid#1458434 to sanitize Untrusted loop bound + nWidth = pBitmap->Width(); + + size_t nByteWidth = static_cast(nWidth) * nCmpCount; + std::vector aScanline(nByteWidth); + for (sal_uInt16 ny = 0; ny < nHeight; ++ny) + { + nSrcBitsPos = pPict->Tell(); + if ( nRowBytes > 250 ) + { + pPict->ReadUInt16( nByteCount ); + nByteCount += 2; + } + else + { + pPict->ReadUChar( nByteCountAsByte ); + nByteCount = nByteCountAsByte; + nByteCount++; + } + size_t i = 0; + while (i < aScanline.size()) + { + pPict->ReadUChar( nFlagCounterByte ); + if ( ( nFlagCounterByte & 0x80 ) == 0) + { + nCount = static_cast(nFlagCounterByte) + 1; + if ((i + nCount) > aScanline.size()) + nCount = aScanline.size() - i; + if (pPict->remainingSize() < nCount) + return 0xffffffff; + while( nCount-- ) + { + pPict->ReadUChar( nDat ); + aScanline[ i++ ] = nDat; + } + } + else + { + if (pPict->remainingSize() < 1) + return 0xffffffff; + nCount = ( 1 - sal_Int16( static_cast(nFlagCounterByte) | 0xff00 ) ); + if (( i + nCount) > aScanline.size()) + nCount = aScanline.size() - i; + pPict->ReadUChar( nDat ); + while( nCount-- ) + aScanline[ i++ ] = nDat; + } + } + sal_uInt8* pTmp = aScanline.data(); + if ( nCmpCount == 4 ) + pTmp += nWidth; + for (sal_uInt16 nx = 0; nx < nWidth; pTmp++) + pBitmap->SetPixel(ny, nx++, Color(*pTmp, pTmp[ nWidth ], pTmp[ 2 * nWidth ])); + nDataSize += nByteCount; + pPict->Seek( nSrcBitsPos + nByteCount ); + } + } + } + } + else + return 0xffffffff; + rBitmap = vcl::bitmap::CreateFromData(std::move(*pBitmap)); + return nDataSize; +} + +void PictReader::ReadHeader() +{ + short y1,x1,y2,x2; + + char sBuf[ 2 ]; + // previous code considers pPict->Tell() as the normal starting position, + // nStartPos can be != 0 f.e. a pict embedded in a microsoft word document + sal_uInt64 nStartPos = pPict->Tell(); + // Standard: + // a picture file begins by 512 bytes (reserved to the application) followed by the picture data + // while clipboard, pictures stored in a document often contain only the picture data. + + // Special cases: + // - some Pict v.1 use 0x00 0x11 0x01 ( instead of 0x11 0x01) to store the version op + // (we consider here this as another standard for Pict. v.1 ) + // - some files seem to contain extra garbage data at the beginning + // - some picture data seem to contain extra NOP opcode(0x00) between the bounding box and the version opcode + + // This code looks hard to find a picture header, ie. it looks at positions + // - nStartPos+0, nStartPos+512 with potential extra NOP codes between bdbox and version (at most 9 extra NOP) + // - 512..1024 with more strict bdbox checking and no extra NOP codes + + // Notes: + // - if the header can begin at nStartPos+0 and at nStartPos+512, we try to choose the more + // <> ( using the variable confidence) + // - svtools/source/filter.vcl/filter/{filter.cxx,filter2.cxx} only check for standard Pict, + // this may cause future problems + int st; + sal_uInt32 nOffset; + int confidence[2] = { 0, 0}; + for ( st = 0; st < 3 + 513; st++ ) + { + int actualConfid = 20; // the actual confidence + pPict->ResetError(); + if (st < 2) nOffset = nStartPos+st*512; + else if (st == 2) { + // choose nStartPos+0 or nStartPos+512 even if there are a little dubious + int actPos = -1, actConf=0; + if (confidence[0] > 0) { actPos = 0; actConf = confidence[0]; } + if (confidence[1] > 0 && confidence[1] >= actConf) actPos = 1; + if (actPos < 0) continue; + nOffset = nStartPos+actPos*512; + } + else { + nOffset = nStartPos+509+st; + // a small test to check if versionOp code exists after the bdbox ( with no extra NOP codes) + pPict->Seek(nOffset+10); + pPict->ReadBytes(sBuf, 2); + if (!pPict->good()) break; + if (sBuf[0] == 0x11 || (sBuf[0] == 0x00 && sBuf[1] == 0x11)) ; // maybe ok + else continue; + } + pPict->Seek(nOffset); + + // 2 bytes to store size ( version 1 ) ignored + pPict->SeekRel( 2 ); + pPict->ReadInt16( y1 ).ReadInt16( x1 ).ReadInt16( y2 ).ReadInt16( x2 ); // frame rectangle of the picture + if (x1 > x2 || y1 > y2) continue; // bad bdbox + if (x1 < -2048 || x2 > 2048 || y1 < -2048 || y2 > 2048 || // origin|dest is very small|large + (x1 == x2 && y1 == y2) ) // 1 pixel pict is dubious + actualConfid-=3; + else if (x2 < x1+8 || y2 < y1+8) // a little dubious + actualConfid-=1; + if (st >= 3 && actualConfid != 20) continue; + aBoundingRect=tools::Rectangle( x1,y1, x2, y2 ); + + if (!pPict->good()) continue; + // read version + pPict->ReadBytes(sBuf, 2); + // version 1 file + if ( sBuf[ 0 ] == 0x11 && sBuf[ 1 ] == 0x01 ) { + // pict v1 must be rare and we do only few tests + if (st < 2) { confidence[st] = --actualConfid; continue; } + IsVersion2 = false; return; + } + if (sBuf[0] != 0x00) continue; // unrecoverable error + int numZero = 0; + do + { + numZero++; + pPict->SeekRel(-1); + pPict->ReadBytes(sBuf, 2); + } + while ( sBuf[0] == 0x00 && numZero < 10); + actualConfid -= (numZero-1); // extra nop are dubious + if (!pPict->good()) continue; + if (sBuf[0] != 0x11) continue; // not a version opcode + // abnormal version 1 file + if (sBuf[1] == 0x01 ) { + // pict v1 must be rare and we do only few tests + if (st < 2) { confidence[st] = --actualConfid; continue; } + IsVersion2 = false; return; + } + if (sBuf[1] != 0x02 ) continue; // not a version 2 file + + IsVersion2=true; + short nExtVer, nReserved; + // 3 Bytes ignored : end of version arg 0x02FF (ie: 0xFF), HeaderOp : 0x0C00 + pPict->SeekRel( 3 ); + pPict->ReadInt16( nExtVer ).ReadInt16( nReserved ); + if (!pPict->good()) continue; + + if ( nExtVer == -2 ) // extended version 2 picture + { + sal_Int32 nHResFixed, nVResFixed; + pPict->ReadInt32( nHResFixed ).ReadInt32( nVResFixed ); + pPict->ReadInt16( y1 ).ReadInt16( x1 ).ReadInt16( y2 ).ReadInt16( x2 ); // reading the optimal bounding rect + if (x1 > x2 || y1 > y2) continue; // bad bdbox + if (st < 2 && actualConfid != 20) { confidence[st] = actualConfid; continue; } + + double fHRes = nHResFixed; + fHRes /= 65536; + double fVRes = nVResFixed; + fVRes /= 65536; + aHRes /= fHRes; + aVRes /= fVRes; + aBoundingRect=tools::Rectangle( x1,y1, x2, y2 ); + pPict->SeekRel( 4 ); // 4 bytes reserved + return; + } + else if (nExtVer == -1 ) { // basic version 2 picture + if (st < 2 && actualConfid != 20) { confidence[st] = actualConfid; continue; } + pPict->SeekRel( 16); // bdbox(4 fixed number) + pPict->SeekRel(4); // 4 bytes reserved + return; + } + } + pPict->SetError(SVSTREAM_FILEFORMAT_ERROR); +} + +#if OSL_DEBUG_LEVEL > 0 +static const char* operationName(sal_uInt16 nOpcode) +{ + // add here whatever makes the debugging easier for you, otherwise you'll + // see only the operation's opcode + switch (nOpcode) + { + case 0x0001: return "Clip"; + case 0x0003: return "TxFont"; + case 0x0004: return "TxFace"; + case 0x0008: return "PnMode"; + case 0x0009: return "PnPat"; + case 0x000d: return "TxSize"; + case 0x001a: return "RGBFgCol"; + case 0x001d: return "HiliteColor"; + case 0x0020: return "Line"; + case 0x0022: return "ShortLine"; + case 0x0028: return "LongText"; + case 0x0029: return "DHText"; + case 0x002a: return "DVText"; + case 0x002c: return "fontName"; + case 0x002e: return "glyphState"; + case 0x0031: return "paintRect"; + case 0x0038: return "frameSameRect"; + case 0x0070: return "framePoly"; + case 0x0071: return "paintPoly"; + case 0x00a1: return "LongComment"; + default: return "?"; + } +} +#endif + +sal_uInt64 PictReader::ReadData(sal_uInt16 nOpcode) +{ + Point aPoint; + sal_uInt64 nDataSize=0; + PictDrawingMethod shapeDMethod = PictDrawingMethod::UNDEFINED; + switch (nOpcode & 7) { + case 0: shapeDMethod = PictDrawingMethod::FRAME; break; + case 1: shapeDMethod = PictDrawingMethod::PAINT; break; + case 2: shapeDMethod = PictDrawingMethod::ERASE; break; + case 3: shapeDMethod = PictDrawingMethod::INVERT; break; + case 4: shapeDMethod = PictDrawingMethod::FILL; break; + default: break; + } + +#if OSL_DEBUG_LEVEL > 0 + SAL_INFO("filter.pict", "Operation: 0x" << OUString::number(nOpcode, 16) << " [" << operationName(nOpcode) << "]"); +#endif + + switch(nOpcode) { + + case 0x0000: // NOP + nDataSize=0; + break; + + case 0x0001: { // Clip + sal_uInt16 nUSHORT(0); + tools::Rectangle aRect; + pPict->ReadUInt16( nUSHORT ); + nDataSize=nUSHORT; + ReadRectangle(aRect); + // checkme: do we really want to extend the rectangle here ? + // I do that because the clipping is often used to clean a region, + // before drawing some text and also to draw this text. + // So using a too small region can lead to clip the end of the text ; + // but this can be discussable... + aRect.setWidth(aRect.getWidth()+1); + aRect.setHeight(aRect.getHeight()+1); + pVirDev->SetClipRegion( vcl::Region( aRect ) ); + break; + } + case 0x0002: // BkPat + nDataSize = eActBackPattern.read(*pPict); + eActMethod = PictDrawingMethod::UNDEFINED; + break; + + case 0x0003: // TxFont + { + sal_uInt16 nUSHORT(0); + pPict->ReadUInt16( nUSHORT ); + if (nUSHORT <= 1) aActFont.SetFamily(FAMILY_SWISS); + else if (nUSHORT <= 12) aActFont.SetFamily(FAMILY_DECORATIVE); + else if (nUSHORT <= 20) aActFont.SetFamily(FAMILY_ROMAN); + else if (nUSHORT == 21) aActFont.SetFamily(FAMILY_SWISS); + else if (nUSHORT == 22) aActFont.SetFamily(FAMILY_MODERN); + else if (nUSHORT <= 1023) aActFont.SetFamily(FAMILY_SWISS); + else aActFont.SetFamily(FAMILY_ROMAN); + aActFont.SetCharSet(GetTextEncoding(nUSHORT)); + eActMethod = PictDrawingMethod::UNDEFINED; + nDataSize=2; + break; + } + case 0x0004: { // TxFace + char nFace(0); + pPict->ReadChar( nFace ); + if ( (nFace & 0x01)!=0 ) aActFont.SetWeight(WEIGHT_BOLD); + else aActFont.SetWeight(WEIGHT_NORMAL); + if ( (nFace & 0x02)!=0 ) aActFont.SetItalic(ITALIC_NORMAL); + else aActFont.SetItalic(ITALIC_NONE); + if ( (nFace & 0x04)!=0 ) aActFont.SetUnderline(LINESTYLE_SINGLE); + else aActFont.SetUnderline(LINESTYLE_NONE); + if ( (nFace & 0x08)!=0 ) aActFont.SetOutline(true); + else aActFont.SetOutline(false); + if ( (nFace & 0x10)!=0 ) aActFont.SetShadow(true); + else aActFont.SetShadow(false); + eActMethod = PictDrawingMethod::UNDEFINED; + nDataSize=1; + break; + } + case 0x0005: // TxMode + nDataSize=2; + break; + + case 0x0006: // SpExtra + nDataSize=4; + break; + + case 0x0007: { // PnSize + nActPenSize=ReadSize(); + eActMethod = PictDrawingMethod::UNDEFINED; + nDataSize=4; + break; + } + case 0x0008: // PnMode + { + sal_uInt16 nUSHORT(0); + pPict->ReadUInt16( nUSHORT ); + // internal code for postscript command (Quickdraw Reference Drawing B-30,B-34) + if (nUSHORT==23) eActROP = RasterOp::N1; + else { + switch (nUSHORT & 0x0007) { + case 0: eActROP=RasterOp::OverPaint; break; // Copy + case 1: eActROP=RasterOp::OverPaint; break; // Or + case 2: eActROP=RasterOp::Xor; break; // Xor + case 3: eActROP=RasterOp::OverPaint; break; // Bic + case 4: eActROP=RasterOp::Invert; break; // notCopy + case 5: eActROP=RasterOp::OverPaint; break; // notOr + case 6: eActROP=RasterOp::Xor; break; // notXor + case 7: eActROP=RasterOp::OverPaint; break; // notBic + } + } + eActMethod = PictDrawingMethod::UNDEFINED; + nDataSize=2; + break; + } + case 0x0009: // PnPat + nDataSize=eActPenPattern.read(*pPict); + eActMethod = PictDrawingMethod::UNDEFINED; + break; + + case 0x000a: // FillPat + nDataSize=eActFillPattern.read(*pPict); + eActMethod = PictDrawingMethod::UNDEFINED; + break; + + case 0x000b: // OvSize + aActOvalSize=ReadSize(); + nDataSize=4; + break; + + case 0x000c: // Origin + nDataSize=4; + break; + + case 0x000d: // TxSize + { + sal_uInt16 nUSHORT(0); + pPict->ReadUInt16( nUSHORT ); + aActFont.SetFontSize( Size( 0, static_cast(nUSHORT) ) ); + eActMethod = PictDrawingMethod::UNDEFINED; + nDataSize=2; + } + break; + + case 0x000e: // FgColor + aActForeColor=ReadColor(); + eActMethod = PictDrawingMethod::UNDEFINED; + nDataSize=4; + break; + + case 0x000f: // BkColor + aActBackColor=ReadColor(); + nDataSize=4; + break; + + case 0x0010: // TxRatio + nDataSize=8; + break; + + case 0x0011: // VersionOp + nDataSize=1; + break; + + case 0x0012: // BkPixPat + nDataSize=ReadPixPattern(eActBackPattern); + eActMethod = PictDrawingMethod::UNDEFINED; + break; + + case 0x0013: // PnPixPat + nDataSize=ReadPixPattern(eActPenPattern); + eActMethod = PictDrawingMethod::UNDEFINED; + break; + + case 0x0014: // FillPixPat + nDataSize=ReadPixPattern(eActFillPattern); + eActMethod = PictDrawingMethod::UNDEFINED; + break; + + case 0x0015: // PnLocHFrac + nDataSize=2; + break; + + case 0x0016: // ChExtra + nDataSize=2; + break; + + case 0x0017: // Reserved (0 Bytes) + case 0x0018: // Reserved (0 Bytes) + case 0x0019: // Reserved (0 Bytes) + nDataSize=0; + break; + + case 0x001a: // RGBFgCol + aActForeColor=ReadRGBColor(); + eActMethod = PictDrawingMethod::UNDEFINED; + nDataSize=6; + break; + + case 0x001b: // RGBBkCol + aActBackColor=ReadRGBColor(); + eActMethod = PictDrawingMethod::UNDEFINED; + nDataSize=6; + break; + + case 0x001c: // HiliteMode + nDataSize=0; + break; + + case 0x001d: // HiliteColor + nDataSize=6; + break; + + case 0x001e: // DefHilite + nDataSize=0; + break; + + case 0x001f: // OpColor + nDataSize=6; + break; + + case 0x0020: // Line + aPoint=ReadPoint(); aPenPosition=ReadPoint(); + nDataSize=8; + + if (!pPict->good()) + break; + + if (IsInvisible( PictDrawingMethod::FRAME )) break; + DrawingMethod( PictDrawingMethod::FRAME ); + PictReaderShape::drawLine(pVirDev, aPoint,aPenPosition, nActPenSize); + break; + + case 0x0021: // LineFrom + aPoint=aPenPosition; aPenPosition=ReadPoint(); + nDataSize=4; + + if (!pPict->good()) + break; + + if (IsInvisible( PictDrawingMethod::FRAME )) break; + DrawingMethod( PictDrawingMethod::FRAME ); + PictReaderShape::drawLine(pVirDev, aPoint,aPenPosition, nActPenSize); + break; + + case 0x0022: // ShortLine + aPoint=ReadPoint(); + aPenPosition=ReadDeltaH(aPoint); + aPenPosition=ReadDeltaV(aPenPosition); + nDataSize=6; + + if (!pPict->good()) + break; + + if ( IsInvisible(PictDrawingMethod::FRAME) ) break; + DrawingMethod( PictDrawingMethod::FRAME ); + PictReaderShape::drawLine(pVirDev, aPoint,aPenPosition, nActPenSize); + break; + + case 0x0023: // ShortLineFrom + aPoint=aPenPosition; + aPenPosition=ReadDeltaH(aPoint); + aPenPosition=ReadDeltaV(aPenPosition); + nDataSize=2; + + if (!pPict->good()) + break; + + if (IsInvisible( PictDrawingMethod::FRAME )) break; + DrawingMethod( PictDrawingMethod::FRAME ); + PictReaderShape::drawLine(pVirDev, aPoint,aPenPosition, nActPenSize); + break; + + case 0x0024: // Reserved (n Bytes) + case 0x0025: // Reserved (n Bytes) + case 0x0026: // Reserved (n Bytes) + case 0x0027: // Reserved (n Bytes) + { + sal_uInt16 nUSHORT(0); + pPict->ReadUInt16( nUSHORT ); + nDataSize=2+nUSHORT; + break; + } + case 0x0028: // LongText + aTextPosition=ReadPoint(); + nDataSize=4+ReadAndDrawText(); + break; + + case 0x0029: // DHText + aTextPosition=ReadUnsignedDeltaH(aTextPosition); + nDataSize=1+ReadAndDrawText(); + break; + + case 0x002a: // DVText + aTextPosition=ReadUnsignedDeltaV(aTextPosition); + nDataSize=1+ReadAndDrawText(); + break; + + case 0x002b: // DHDVText + aTextPosition=ReadUnsignedDeltaH(aTextPosition); + aTextPosition=ReadUnsignedDeltaV(aTextPosition); + nDataSize=2+ReadAndDrawText(); + break; + + case 0x002c: { // fontName + sal_uInt16 nUSHORT(0); + pPict->ReadUInt16( nUSHORT ); nDataSize=nUSHORT+2; + pPict->ReadUInt16( nUSHORT ); + if (nUSHORT <= 1) aActFont.SetFamily(FAMILY_SWISS); + else if (nUSHORT <= 12) aActFont.SetFamily(FAMILY_DECORATIVE); + else if (nUSHORT <= 20) aActFont.SetFamily(FAMILY_ROMAN); + else if (nUSHORT == 21) aActFont.SetFamily(FAMILY_SWISS); + else if (nUSHORT == 22) aActFont.SetFamily(FAMILY_MODERN); + else if (nUSHORT <= 1023) aActFont.SetFamily(FAMILY_SWISS); + else aActFont.SetFamily(FAMILY_ROMAN); + aActFont.SetCharSet(GetTextEncoding(nUSHORT)); + char nByteLen(0); + pPict->ReadChar( nByteLen ); + sal_uInt16 nLen = static_cast(nByteLen)&0x00ff; + char sFName[ 256 ]; + sFName[pPict->ReadBytes(sFName, nLen)] = 0; + OUString aString( sFName, strlen(sFName), osl_getThreadTextEncoding() ); + aActFont.SetFamilyName( aString ); + eActMethod = PictDrawingMethod::UNDEFINED; + break; + } + case 0x002d: // lineJustify + nDataSize=10; + break; + + case 0x002e: // glyphState + { + sal_uInt16 nUSHORT(0); + pPict->ReadUInt16( nUSHORT ); + nDataSize=2+nUSHORT; + break; + } + case 0x002f: // Reserved (n Bytes) + { + sal_uInt16 nUSHORT(0); + pPict->ReadUInt16( nUSHORT ); + nDataSize=2+nUSHORT; + break; + } + case 0x0030: // frameRect + case 0x0031: // paintRect + case 0x0032: // eraseRect + case 0x0033: // invertRect + case 0x0034: // fillRect + nDataSize=ReadAndDrawRect(shapeDMethod); + break; + + case 0x0035: // Reserved (8 Bytes) + case 0x0036: // Reserved (8 Bytes) + case 0x0037: // Reserved (8 Bytes) + nDataSize=8; + break; + + case 0x0038: // frameSameRect + case 0x0039: // paintSameRect + case 0x003a: // eraseSameRect + case 0x003b: // invertSameRect + case 0x003c: // fillSameRect + nDataSize=ReadAndDrawSameRect(shapeDMethod); + break; + + case 0x003d: // Reserved (0 Bytes) + case 0x003e: // Reserved (0 Bytes) + case 0x003f: // Reserved (0 Bytes) + nDataSize=0; + break; + + case 0x0040: // frameRRect + case 0x0041: // paintRRect + case 0x0042: // eraseRRect + case 0x0043: // invertRRect + case 0x0044: // fillRRect + nDataSize=ReadAndDrawRoundRect(shapeDMethod); + break; + + case 0x0045: // Reserved (8 Bytes) + case 0x0046: // Reserved (8 Bytes) + case 0x0047: // Reserved (8 Bytes) + nDataSize=8; + break; + + case 0x0048: // frameSameRRect + case 0x0049: // paintSameRRect + case 0x004a: // eraseSameRRect + case 0x004b: // invertSameRRect + case 0x004c: // fillSameRRect + nDataSize=ReadAndDrawSameRoundRect(shapeDMethod); + break; + + case 0x004d: // Reserved (0 Bytes) + case 0x004e: // Reserved (0 Bytes) + case 0x004f: // Reserved (0 Bytes) + nDataSize=0; + break; + + case 0x0050: // frameOval + case 0x0051: // paintOval + case 0x0052: // eraseOval + case 0x0053: // invertOval + case 0x0054: // fillOval + nDataSize=ReadAndDrawOval(shapeDMethod); + break; + + case 0x0055: // Reserved (8 Bytes) + case 0x0056: // Reserved (8 Bytes) + case 0x0057: // Reserved (8 Bytes) + nDataSize=8; + break; + + case 0x0058: // frameSameOval + case 0x0059: // paintSameOval + case 0x005a: // eraseSameOval + case 0x005b: // invertSameOval + case 0x005c: // fillSameOval + nDataSize=ReadAndDrawSameOval(shapeDMethod); + break; + + case 0x005d: // Reserved (0 Bytes) + case 0x005e: // Reserved (0 Bytes) + case 0x005f: // Reserved (0 Bytes) + nDataSize=0; + break; + + case 0x0060: // frameArc + case 0x0061: // paintArc + case 0x0062: // eraseArc + case 0x0063: // invertArc + case 0x0064: // fillArc + nDataSize=ReadAndDrawArc(shapeDMethod); + break; + + case 0x0065: // Reserved (12 Bytes) + case 0x0066: // Reserved (12 Bytes) + case 0x0067: // Reserved (12 Bytes) + nDataSize=12; + break; + + case 0x0068: // frameSameArc + case 0x0069: // paintSameArc + case 0x006a: // eraseSameArc + case 0x006b: // invertSameArc + case 0x006c: // fillSameArc + nDataSize=ReadAndDrawSameArc(shapeDMethod); + break; + + case 0x006d: // Reserved (4 Bytes) + case 0x006e: // Reserved (4 Bytes) + case 0x006f: // Reserved (4 Bytes) + nDataSize=4; + break; + + case 0x0070: // framePoly + case 0x0071: // paintPoly + case 0x0072: // erasePoly + case 0x0073: // invertPoly + case 0x0074: // fillPoly + nDataSize=ReadAndDrawPolygon(shapeDMethod); + break; + + case 0x0075: // Reserved (Polygon-Size) + case 0x0076: // Reserved (Polygon-Size) + case 0x0077: // Reserved (Polygon-Size) + { + sal_uInt16 nUSHORT(0); + pPict->ReadUInt16( nUSHORT ); nDataSize=nUSHORT; + break; + } + case 0x0078: // frameSamePoly + case 0x0079: // paintSamePoly + case 0x007a: // eraseSamePoly + case 0x007b: // invertSamePoly + case 0x007c: // fillSamePoly + nDataSize=ReadAndDrawSamePolygon(shapeDMethod); + break; + + case 0x007d: // Reserved (0 Bytes) + case 0x007e: // Reserved (0 Bytes) + case 0x007f: // Reserved (0 Bytes) + nDataSize=0; + break; + + case 0x0080: // frameRgn + case 0x0081: // paintRgn + case 0x0082: // eraseRgn + case 0x0083: // invertRgn + case 0x0084: // fillRgn + nDataSize=ReadAndDrawRgn(shapeDMethod); + break; + + case 0x0085: // Reserved (Region-Size) + case 0x0086: // Reserved (Region-Size) + case 0x0087: // Reserved (Region-Size) + { + sal_uInt16 nUSHORT(0); + pPict->ReadUInt16( nUSHORT ); nDataSize=nUSHORT; + break; + } + case 0x0088: // frameSameRgn + case 0x0089: // paintSameRgn + case 0x008a: // eraseSameRgn + case 0x008b: // invertSameRgn + case 0x008c: // fillSameRgn + nDataSize=ReadAndDrawSameRgn(shapeDMethod); + break; + + case 0x008d: // Reserved (0 Bytes) + case 0x008e: // Reserved (0 Bytes) + case 0x008f: // Reserved (0 Bytes) + nDataSize=0; + break; + + case 0x0090: { // BitsRect + BitmapEx aBmp; + tools::Rectangle aSrcRect, aDestRect; + nDataSize=ReadPixMapEtc(aBmp, false, true, &aSrcRect, &aDestRect, true, false); + DrawingMethod( PictDrawingMethod::PAINT ); + pVirDev->DrawBitmapEx(aDestRect.TopLeft(),aDestRect.GetSize(),aBmp); + break; + } + case 0x0091: { // BitsRgn + BitmapEx aBmp; + tools::Rectangle aSrcRect, aDestRect; + nDataSize=ReadPixMapEtc(aBmp, false, true, &aSrcRect, &aDestRect, true, true); + DrawingMethod( PictDrawingMethod::PAINT ); + pVirDev->DrawBitmapEx(aDestRect.TopLeft(),aDestRect.GetSize(),aBmp); + break; + } + case 0x0092: // Reserved (n Bytes) + case 0x0093: // Reserved (n Bytes) + case 0x0094: // Reserved (n Bytes) + case 0x0095: // Reserved (n Bytes) + case 0x0096: // Reserved (n Bytes) + case 0x0097: // Reserved (n Bytes) + { + sal_uInt16 nUSHORT(0); + pPict->ReadUInt16( nUSHORT ); nDataSize=2+nUSHORT; + break; + } + case 0x0098: { // PackBitsRect + BitmapEx aBmp; + tools::Rectangle aSrcRect, aDestRect; + nDataSize=ReadPixMapEtc(aBmp, false, true, &aSrcRect, &aDestRect, true, false); + DrawingMethod( PictDrawingMethod::PAINT ); + pVirDev->DrawBitmapEx(aDestRect.TopLeft(),aDestRect.GetSize(),aBmp); + break; + } + case 0x0099: { // PackBitsRgn + BitmapEx aBmp; + tools::Rectangle aSrcRect, aDestRect; + nDataSize=ReadPixMapEtc(aBmp, false, true, &aSrcRect, &aDestRect, true, true); + DrawingMethod( PictDrawingMethod::PAINT ); + pVirDev->DrawBitmapEx(aDestRect.TopLeft(),aDestRect.GetSize(),aBmp); + break; + } + case 0x009a: { // DirectBitsRect + BitmapEx aBmp; + tools::Rectangle aSrcRect, aDestRect; + nDataSize=ReadPixMapEtc(aBmp, true, false, &aSrcRect, &aDestRect, true, false); + DrawingMethod( PictDrawingMethod::PAINT ); + pVirDev->DrawBitmapEx(aDestRect.TopLeft(),aDestRect.GetSize(),aBmp); + break; + } + case 0x009b: { // DirectBitsRgn + BitmapEx aBmp; + tools::Rectangle aSrcRect, aDestRect; + nDataSize=ReadPixMapEtc(aBmp, true, false, &aSrcRect, &aDestRect, true, true); + DrawingMethod( PictDrawingMethod::PAINT ); + pVirDev->DrawBitmapEx(aDestRect.TopLeft(),aDestRect.GetSize(),aBmp); + break; + } + case 0x009c: // Reserved (n Bytes) + case 0x009d: // Reserved (n Bytes) + case 0x009e: // Reserved (n Bytes) + case 0x009f: // Reserved (n Bytes) + { + sal_uInt16 nUSHORT(0); + pPict->ReadUInt16( nUSHORT ); nDataSize=2+nUSHORT; + break; + } + case 0x00a0: // ShortComment + nDataSize=2; + break; + + case 0x00a1: // LongComment + { + sal_uInt16 nUSHORT(0); + pPict->SeekRel(2); pPict->ReadUInt16( nUSHORT ); nDataSize=4+nUSHORT; + break; + } + default: // 0x00a2 bis 0xffff (most times reserved) + sal_uInt16 nUSHORT(0); + if (nOpcode<=0x00af) { pPict->ReadUInt16( nUSHORT ); nDataSize=2+nUSHORT; } + else if (nOpcode<=0x00cf) { nDataSize=0; } + else if (nOpcode<=0x00fe) { sal_uInt32 nTemp(0); pPict->ReadUInt32(nTemp) ; nDataSize = nTemp; nDataSize+=4; } + // Osnola: checkme: in the Quickdraw Ref examples ( for pict v2) + // 0x00ff(EndOfPict) is also not followed by any data... + else if (nOpcode==0x00ff) { nDataSize=IsVersion2 ? 2 : 0; } // OpEndPic + else if (nOpcode<=0x01ff) { nDataSize=2; } + else if (nOpcode<=0x0bfe) { nDataSize=4; } + else if (nOpcode<=0x0bff) { nDataSize=22; } + else if (nOpcode==0x0c00) { nDataSize=24; } // HeaderOp + else if (nOpcode<=0x7eff) { nDataSize=24; } + else if (nOpcode<=0x7fff) { nDataSize=254; } + else if (nOpcode<=0x80ff) { nDataSize=0; } + else { sal_uInt32 nTemp(0); pPict->ReadUInt32(nTemp) ; nDataSize = nTemp; nDataSize+=4; } + } + + if (nDataSize==0xffffffff) { + pPict->SetError(SVSTREAM_FILEFORMAT_ERROR); + return 0; + } + return nDataSize; +} + +void PictReader::ReadPict( SvStream & rStreamPict, GDIMetaFile & rGDIMetaFile ) +{ + try { + sal_uInt16 nOpcode; + sal_uInt8 nOneByteOpcode; + sal_uInt64 nSize; + + pPict = &rStreamPict; + nOrigPos = pPict->Tell(); + SvStreamEndian nOrigNumberFormat = pPict->GetEndian(); + + aActForeColor = COL_BLACK; + aActBackColor = COL_WHITE; + nActPenSize = Size(1,1); + eActROP = RasterOp::OverPaint; + eActMethod = PictDrawingMethod::UNDEFINED; + aActOvalSize = Size(1,1); + + aActFont.SetCharSet( GetTextEncoding()); + aActFont.SetFamily(FAMILY_SWISS); + aActFont.SetFontSize(Size(0,12)); + aActFont.SetAlignment(ALIGN_BASELINE); + + aHRes = aVRes = Fraction( 1, 1 ); + + pVirDev = VclPtr::Create(); + pVirDev->EnableOutput(false); + rGDIMetaFile.Record(pVirDev); + + pPict->SetEndian(SvStreamEndian::BIG); + + ReadHeader(); + + aPenPosition=Point(-aBoundingRect.Left(),-aBoundingRect.Top()); + aTextPosition=aPenPosition; + + sal_uInt64 nPos=pPict->Tell(); + + for (;;) { + + if (IsVersion2 ) + pPict->ReadUInt16( nOpcode ); + else + { + pPict->ReadUChar( nOneByteOpcode ); + nOpcode=static_cast(nOneByteOpcode); + } + + if (pPict->GetError()) + break; + + if (pPict->eof()) + { + pPict->SetError(SVSTREAM_FILEFORMAT_ERROR); + break; + } + + if (nOpcode==0x00ff) + break; + + nSize=ReadData(nOpcode); + + if ( IsVersion2 ) + { + if ( nSize & 1 ) + nSize++; + + nPos+=2+nSize; + } + else + nPos+=1+nSize; + + if (!checkSeek(*pPict, nPos)) + { + pPict->SetError(SVSTREAM_FILEFORMAT_ERROR); + break; + } + } + + pVirDev->SetClipRegion(); + rGDIMetaFile.Stop(); + pVirDev.disposeAndClear(); + + rGDIMetaFile.SetPrefMapMode( MapMode( MapUnit::MapInch, Point(), aHRes, aVRes ) ); + rGDIMetaFile.SetPrefSize( aBoundingRect.GetSize() ); + + pPict->SetEndian(nOrigNumberFormat); + + if (pPict->GetError()) pPict->Seek(nOrigPos); + } catch (...) + { + rStreamPict.SetError(SVSTREAM_FILEFORMAT_ERROR); + } +} + +void ReadPictFile(SvStream &rStreamPict, GDIMetaFile& rGDIMetaFile) +{ + PictReader aPictReader; + aPictReader.ReadPict(rStreamPict, rGDIMetaFile); +} + +//================== GraphicImport - the exported function ================ + +bool ImportPictGraphic( SvStream& rIStm, Graphic & rGraphic) +{ + GDIMetaFile aMTF; + bool bRet = false; + + ReadPictFile(rIStm, aMTF); + + if ( !rIStm.GetError() ) + { + rGraphic = Graphic( aMTF ); + bRet = true; + } + + return bRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/filter/ipict/shape.cxx b/vcl/source/filter/ipict/shape.cxx new file mode 100644 index 000000000..88a62cfd2 --- /dev/null +++ b/vcl/source/filter/ipict/shape.cxx @@ -0,0 +1,259 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +/** Osnola: +IMPORTANT NOTE: some Quickdraw lines/frames can not be "quickly" drawn exactly: +for instance, when PenSize=(1,1), the line from (0,0) to (8,0) +corresponds to the rectangle (0,0)(0,1)(9,1)(9,0), which can only be drawn + by drawing a rectangle. Drawing a non horizontal/vertical will imply to draw +a polygon, ... +Similarly, drawing the frame of a rectangle (0,0)(0,1)(9,1)(9,0) when PenSize=(1,1), +will imply to draw a rectangle (0.5,0.5)(0.5,8.5)(8.5,8.5)(8.5,0.5) with linewidth=1... + +Here, we choose: +- for horizontal/vertical lines and line with length less than five to draw the real line, +- in the other case, we keep the same shape (even if this means some "bad" coordinates) +*/ + +#include +#include +#include "shape.hxx" + +namespace PictReaderShapePrivate { + /** returns an inside rectangle knowing the penSize in order to obtain the ``correct'' position + when we draw a frame in wide length*/ + static tools::Rectangle contractRectangle(bool drawFrame, tools::Rectangle const &rect, Size const &pSize) { + if (!drawFrame) return rect; + tools::Long penSize=(pSize.Width()+pSize.Height())/2; + if (2*penSize > rect.Right()-rect.Left()) penSize = (rect.Right()-rect.Left()+1)/2; + if (2*penSize > rect.Bottom()-rect.Top()) penSize = (rect.Bottom()-rect.Top()+1)/2; + tools::Long const X[2] = { rect.Left()+penSize/2, rect.Right()-(penSize+1)/2 }; + tools::Long const Y[2] = { rect.Top()+penSize/2, rect.Bottom()-(penSize+1)/2 }; + return tools::Rectangle(Point(X[0],Y[0]), Point(X[1], Y[1])); + } +} + +namespace PictReaderShape { + //--------- draws a horizontal/vertical/small line (by creating a "rectangle/polygon") --------- + static bool drawLineHQ(VirtualDevice *dev, Point const &orig, Point const &dest, Size const &pSize) { + tools::Long dir[2] = { dest.X()-orig.X(), dest.Y()-orig.Y() }; + bool vertic = dir[0] == 0; + bool horiz = dir[1] == 0; + if (!horiz && !vertic && dir[0]*dir[0]+dir[1]*dir[1] > 25) return false; + + using namespace basegfx; + B2DPolygon poly; + if (horiz || vertic) { + tools::Long X[2]={ orig.X(), dest.X() }, Y[2] = { orig.Y(), dest.Y() }; + if (horiz) { + if (X[0] < X[1]) X[1]+=pSize.Width(); + else X[0]+=pSize.Width(); + Y[1] += pSize.Height(); + } + else { + if (Y[0] < Y[1]) Y[1]+=pSize.Height(); + else Y[0]+=pSize.Height(); + X[1] += pSize.Width(); + } + poly.append(B2DPoint(X[0], Y[0])); poly.append(B2DPoint(X[1], Y[0])); + poly.append(B2DPoint(X[1], Y[1])); poly.append(B2DPoint(X[0], Y[1])); + poly.append(B2DPoint(X[0], Y[0])); + } + else { + tools::Long origPt[4][2] = { { orig.X(), orig.Y() }, { orig.X()+pSize.Width(), orig.Y() }, + { orig.X()+pSize.Width(), orig.Y()+pSize.Height() }, + { orig.X(), orig.Y()+pSize.Height() }}; + int origAvoid = dir[0] > 0 ? (dir[1] > 0 ? 2 : 1) : (dir[1] > 0 ? 3 : 0); + tools::Long destPt[4][2] = { { dest.X(), dest.Y() }, { dest.X()+pSize.Width(), dest.Y() }, + { dest.X()+pSize.Width(), dest.Y()+pSize.Height() }, + { dest.X(), dest.Y()+pSize.Height() }}; + for (int w = origAvoid+1; w < origAvoid+4; w++) { + int wh = w%4; + poly.append(B2DPoint(origPt[wh][0], origPt[wh][1])); + } + for (int w = origAvoid+3; w < origAvoid+6; w++) { + int wh = w%4; + poly.append(B2DPoint(destPt[wh][0], destPt[wh][1])); + } + int wh = (origAvoid+1)%4; + poly.append(B2DPoint(origPt[wh][0], origPt[wh][1])); + } + + // HACK: here we use the line coloring when drawing the shape + // must be changed if other parameter are changed to draw + // a line/fill shape + Color oldFColor = dev->GetFillColor(), oldLColor = dev->GetLineColor(); + dev->SetFillColor(oldLColor); dev->SetLineColor(COL_TRANSPARENT); + dev->DrawPolygon(poly); + dev->SetLineColor(oldLColor); dev->SetFillColor(oldFColor); + return true; + } + + + //-------------------- draws a line -------------------- + + void drawLine(VirtualDevice *dev, Point const &orig, Point const &dest, Size const &pSize) { + if (drawLineHQ(dev,orig,dest,pSize)) return; + + tools::Long penSize=(pSize.Width()+pSize.Height())/2; + tools::Long decal[2] = { pSize.Width()/2, pSize.Height()/2}; + + using namespace basegfx; + B2DPolygon poly; + poly.append(B2DPoint(double(orig.X()+decal[0]), double(orig.Y()+decal[1]))); + poly.append(B2DPoint(double(dest.X()+decal[0]), double(dest.Y()+decal[1]))); + dev->DrawPolyLine(poly, double(penSize), basegfx::B2DLineJoin::NONE); + } + + //-------------------- draws a rectangle -------------------- + /* Note(checkme): contradictally with the QuickDraw's reference 3-23, it seems better to consider + that the frame/content of a rectangle appears inside the given rectangle. Does a conversion + appear between the pascal functions and the data stored in the file ? */ + void drawRectangle(VirtualDevice *dev, bool drawFrame, tools::Rectangle const &orig, Size const &pSize) { + int penSize=(pSize.Width()+pSize.Height())/2; + tools::Rectangle rect = PictReaderShapePrivate::contractRectangle(drawFrame, orig, pSize); + tools::Long const X[2] = { rect.Left(), rect.Right() }; + tools::Long const Y[2] = { rect.Top(), rect.Bottom() }; + + using namespace basegfx; + B2DPolygon poly; + poly.append(B2DPoint(X[0], Y[0])); poly.append(B2DPoint(X[1], Y[0])); + poly.append(B2DPoint(X[1], Y[1])); poly.append(B2DPoint(X[0], Y[1])); + poly.append(B2DPoint(X[0], Y[0])); + + if (drawFrame) + dev->DrawPolyLine(poly, double(penSize), basegfx::B2DLineJoin::NONE); + else + dev->DrawPolygon(poly); + } + + //-------------------- draws an ellipse -------------------- + void drawEllipse(VirtualDevice *dev, bool drawFrame, tools::Rectangle const &orig, Size const &pSize) { + int penSize=(pSize.Width()+pSize.Height())/2; + tools::Rectangle oval = PictReaderShapePrivate::contractRectangle(drawFrame, orig, pSize); + using namespace basegfx; + tools::Long const X[2] = { oval.Left(), oval.Right() }; + tools::Long const Y[2] = { oval.Top(), oval.Bottom() }; + B2DPoint center(0.5*(X[1]+X[0]), 0.5*(Y[1]+Y[0])); + B2DPolygon poly = basegfx::utils::createPolygonFromEllipse(center, 0.5*(X[1]-X[0]), 0.5*(Y[1]-Y[0])); + if (drawFrame) + dev->DrawPolyLine(poly, double(penSize), basegfx::B2DLineJoin::NONE); + else + dev->DrawPolygon(poly); + } + + //-------------------- draws an arc/pie -------------------- + void drawArc(VirtualDevice *dev, bool drawFrame, tools::Rectangle const &orig, const double& angle1, const double& angle2, Size const &pSize) { + int penSize=(pSize.Width()+pSize.Height())/2; + tools::Rectangle arc = PictReaderShapePrivate::contractRectangle(drawFrame, orig, pSize); + using namespace basegfx; + + // pict angle are CW with 0 at twelve o'clock (with Y-axis inverted)... + double angl1 = angle1-M_PI_2; + double angl2 = angle2-M_PI_2; + tools::Long const X[2] = { arc.Left(), arc.Right() }; + tools::Long const Y[2] = { arc.Top(), arc.Bottom() }; + B2DPoint center(0.5*(X[1]+X[0]), 0.5*(Y[1]+Y[0])); + + // We must have angl1 between 0 and 2PI + while (angl1 < 0.0) { angl1 += 2 * M_PI; angl2 += 2 * M_PI; } + while (angl1 >= 2 * M_PI) { angl1 -= 2 * M_PI; angl2 -= 2 * M_PI; } + + // if this happen, we want a complete circle + // so we set angl2 slightly less than angl1 + if (angl2 >= angl1 + 2 * M_PI) angl2 = angl1-0.001; + + // We must have angl2 between 0 and 2PI + while (angl2 < 0.0) angl2 += 2 * M_PI; + while (angl2 >= 2 * M_PI) angl2 -= 2 * M_PI; + + B2DPolygon poly = basegfx::utils::createPolygonFromEllipseSegment(center, 0.5*(X[1]-X[0]), 0.5*(Y[1]-Y[0]), angl1, angl2); + if (drawFrame) + dev->DrawPolyLine(poly, double(penSize), basegfx::B2DLineJoin::NONE); + else { + // adds circle's center + poly.append(center); + dev->DrawPolygon(poly); + } + } + //-------------------- draws a rectangle with round corner -------------------- + void drawRoundRectangle(VirtualDevice *dev, bool drawFrame, tools::Rectangle const &orig, Size const &ovalSize, Size const &pSize) { + int penSize=(pSize.Width()+pSize.Height())/2; + tools::Rectangle oval = PictReaderShapePrivate::contractRectangle(drawFrame, orig, pSize); + int ovalW=ovalSize.Width(), ovalH=ovalSize.Height(); + using namespace basegfx; + tools::Long const X[2] = { oval.Left(), oval.Right() }; + tools::Long const Y[2] = { oval.Top(), oval.Bottom() }; + tools::Long width = X[1] - X[0]; + tools::Long height = Y[1] - Y[0]; + if (ovalW > width) ovalW = static_cast< int >( width ); + if (ovalH > height) ovalH = static_cast< int >( height ); + + B2DRectangle rect(B2DPoint(X[0],Y[0]), B2DPoint(X[1],Y[1])); + B2DPolygon poly = basegfx::utils::createPolygonFromRect(rect, (width != 0.0) ? ovalW/width : 0.0, (height != 0.0) ? ovalH/height : 0.0); + + if (drawFrame) + dev->DrawPolyLine(poly, double(penSize), basegfx::B2DLineJoin::NONE); + else + dev->DrawPolygon(poly); + } + + //-------------------- draws a polygon -------------------- +void drawPolygon(VirtualDevice *dev, bool drawFrame, tools::Polygon const &orig, Size const &pSize) { + int penSize=(pSize.Width()+pSize.Height())/2; + tools::Long decalTL[2] = {0, 0}, decalBR[2] = { pSize.Width(), pSize.Height()}; + if (drawFrame) { + decalTL[0] += penSize/2; decalTL[1] += penSize/2; + decalBR[0] -= (penSize+1)/2; decalBR[1] -= (penSize+1)/2; + } + // Quickdraw Drawing Reference 3-82: the pen size is only used for frame + else decalBR[0] = decalBR[1] = 0; + + + int numPt = orig.GetSize(); + if (numPt <= 1) return; + + // we compute a barycenter of the point to define the extended direction of each point + double bary[2] = { 0.0, 0.0 }; + for (int i = 0; i < numPt; i++) { + Point const &pt = orig.GetPoint(i); + bary[0] += double(pt.X()); bary[1] += double(pt.Y()); + } + bary[0]/=double(numPt); bary[1]/=double(numPt); + + using namespace basegfx; + B2DPolygon poly; + poly.reserve(numPt); + // Note: a polygon can be open, so we must not close it when we draw the frame + for (int i = 0; i < numPt; i++) { + Point const &pt = orig.GetPoint(i); + double x = (double(pt.X()) < bary[0]) ? pt.X()+decalTL[0] : pt.X()+decalBR[0]; + double y = (double(pt.Y()) < bary[1]) ? pt.Y()+decalTL[1] : pt.Y()+decalBR[1]; + poly.append(B2DPoint(x, y)); + } + if (drawFrame) + dev->DrawPolyLine(poly, double(penSize), basegfx::B2DLineJoin::NONE); + else + dev->DrawPolygon(poly); + } + + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/filter/ipict/shape.hxx b/vcl/source/filter/ipict/shape.hxx new file mode 100644 index 000000000..bccd39e63 --- /dev/null +++ b/vcl/source/filter/ipict/shape.hxx @@ -0,0 +1,57 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#ifndef INCLUDED_FILTER_SOURCE_GRAPHICFILTER_IPICT_SHAPE_HXX +#define INCLUDED_FILTER_SOURCE_GRAPHICFILTER_IPICT_SHAPE_HXX + +#include + +namespace PictReaderShape { + /** draws a line from orig to dest knowing penSize + + Attention: in order to draw horizontal/vertical/small lines, this function can instead draw a rectangle or + a polygon. In this case, we retrieve the line information from VirtualDev ( GetLineColor ) + and we use them as fill information ( SetFillColor ). We restore after the VirtualDev state. + + This implies also that this function must be modified if we use real pattern to draw these primitives. + */ + void drawLine(VirtualDevice *dev, Point const &orig, Point const &dest, Size const &pSize); + + /** draws a rectangle knowing penSize */ + void drawRectangle(VirtualDevice *dev, bool drawFrame, tools::Rectangle const &rect, Size const &pSize); + + /** draws a polygon knowing penSize */ +void drawPolygon(VirtualDevice *dev, bool drawFrame, tools::Polygon const &rect, Size const &pSize); + + /** draws an ellipse knowing penSize */ + void drawEllipse(VirtualDevice *dev, bool drawFrame, tools::Rectangle const &orig, Size const &pSize); + + /** draws a rounded rectangle knowing penSize + \note ovalSize is two time the size of the corner + */ + void drawRoundRectangle(VirtualDevice *dev, bool drawFrame, tools::Rectangle const &orig, Size const &ovalS, Size const &pSize); + + /** draws an arc in a b2dpolygon knowing penSize + \note - it supposes that angl1 < angl2 + */ + void drawArc(VirtualDevice *dev, bool drawFrame, tools::Rectangle const &orig, const double& angle1, const double& angle2, Size const &pSize); +} + +#endif // INCLUDED_FILTER_SOURCE_GRAPHICFILTER_IPICT_SHAPE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ -- cgit v1.2.3