summaryrefslogtreecommitdiffstats
path: root/vcl/source/filter/ipict
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--vcl/source/filter/ipict/ipict.cxx2041
-rw-r--r--vcl/source/filter/ipict/shape.cxx259
-rw-r--r--vcl/source/filter/ipict/shape.hxx57
3 files changed, 2357 insertions, 0 deletions
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 <filter/PictReader.hxx>
+#include <string.h>
+#include <osl/thread.h>
+#include <sal/log.hxx>
+#include <vcl/BitmapTools.hxx>
+#include <vcl/graph.hxx>
+#include <vcl/gdimtf.hxx>
+#include <tools/poly.hxx>
+#include <tools/fract.hxx>
+#include <tools/stream.hxx>
+#include <vcl/virdev.hxx>
+#include <math.h>
+#include "shape.hxx"
+#include <memory>
+
+#include <vcl/FilterConfigItem.hxx>
+ // 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<char&>(ny) );
+ for (short nx=0; nx<8; nx++) {
+ if ( (ny & (1<<nx)) != 0 ) nBitCount++;
+ }
+ }
+
+ // store pattern in 2 long words:
+ sal_uInt32 nHiBytes = (((((static_cast<sal_uInt32>(nbyte[0])<<8)|
+ static_cast<sal_uInt32>(nbyte[1]))<<8)|
+ static_cast<sal_uInt32>(nbyte[2]))<<8)|
+ static_cast<sal_uInt32>(nbyte[3]);
+ sal_uInt32 nLoBytes = (((((static_cast<sal_uInt32>(nbyte[4])<<8)|
+ static_cast<sal_uInt32>(nbyte[5]))<<8)|
+ static_cast<sal_uInt32>(nbyte[6]))<<8)|
+ static_cast<sal_uInt32>(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<VirtualDevice> 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<Color> 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<char&>(ndh) );
+
+ return Point( aBase.X() + static_cast<tools::Long>(ndh), aBase.Y() );
+}
+
+Point PictReader::ReadDeltaV(Point aBase)
+{
+ signed char ndv(0);
+
+ pPict->ReadChar( reinterpret_cast<char&>(ndv) );
+
+ return Point( aBase.X(), aBase.Y() + static_cast<tools::Long>(ndv) );
+}
+
+Point PictReader::ReadUnsignedDeltaH(Point aBase)
+{
+ sal_uInt8 ndh(0);
+
+ pPict->ReadUChar( ndh );
+
+ return Point( aBase.X() + static_cast<tools::Long>(ndh), aBase.Y() );
+}
+
+Point PictReader::ReadUnsignedDeltaV(Point aBase)
+{
+ sal_uInt8 ndv(0);
+
+ pPict->ReadUChar( ndv );
+
+ return Point( aBase.X(), aBase.Y() + static_cast<tools::Long>(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<sal_uInt8>( nR >> 8 ), static_cast<sal_uInt8>( nG >> 8 ), static_cast<sal_uInt8>( 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<sal_uInt64>(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<sal_uInt8>( nR >> 8 ), static_cast<sal_uInt8>( nG >> 8 ), static_cast<sal_uInt8>( 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<double>(nstartAngle) * pi / 180.0;
+ double fAng2 = static_cast<double>(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<sal_uInt64>(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<sal_uInt32>(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<unsigned char>(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<vcl::bitmap::RawBitmap> 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<Color> 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<sal_uInt32>(nByteCount);
+ }
+ else
+ {
+ sal_uInt8 nByteCountAsByte(0);
+ pPict->ReadUChar( nByteCountAsByte );
+ nByteCount = static_cast<sal_uInt16>(nByteCountAsByte) & 0x00ff;
+ nDataSize += 1 + nByteCount;
+ }
+
+ while (pPict->good() && nByteCount)
+ {
+ sal_uInt8 nFlagCounterByte(0);
+ pPict->ReadUChar(nFlagCounterByte);
+ if ( ( nFlagCounterByte & 0x80 ) == 0 )
+ {
+ nCount = static_cast<sal_uInt16>(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<sal_uInt16>( 1 - sal_Int16( static_cast<sal_uInt16>(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<sal_uInt8>( nD >> 7 );
+ nGreen = static_cast<sal_uInt8>( nD >> 2 );
+ nBlue = static_cast<sal_uInt8>( nD << 3 );
+ pBitmap->SetPixel(ny, nx++, Color(nRed, nGreen, nBlue));
+ }
+ nDataSize += static_cast<sal_uInt32>(nWidth) * 2;
+ }
+ else
+ {
+ nSrcBitsPos = pPict->Tell();
+ if ( nRowBytes > 250 )
+ {
+ pPict->ReadUInt16( nByteCount );
+ nByteCount += 2;
+ }
+ else
+ {
+ pPict->ReadUChar( nByteCountAsByte );
+ nByteCount = static_cast<sal_uInt16>(nByteCountAsByte) & 0x00ff;
+ nByteCount++;
+ }
+ while ( nx != nWidth )
+ {
+ pPict->ReadUChar( nFlagCounterByte );
+ if ( (nFlagCounterByte & 0x80) == 0)
+ {
+ nCount=static_cast<sal_uInt16>(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<sal_uInt8>( nD >> 7 );
+ nGreen = static_cast<sal_uInt8>( nD >> 2 );
+ nBlue = static_cast<sal_uInt8>( 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<sal_uInt16>(nFlagCounterByte)|0xff00));
+ if ( nCount + nx > nWidth )
+ nCount = nWidth - nx;
+ pPict->ReadUInt16( nD );
+ nRed = static_cast<sal_uInt8>( nD >> 7 );
+ nGreen = static_cast<sal_uInt8>( nD >> 2 );
+ nBlue = static_cast<sal_uInt8>( 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<sal_uInt32>(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<sal_uInt32>(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<size_t>(nWidth) * nCmpCount;
+ std::vector<sal_uInt8> 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<sal_uInt16>(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<sal_uInt16>(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
+ // <<probable>> ( 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<tools::Long>(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<sal_uInt16>(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<VirtualDevice>::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<sal_uInt16>(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 <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#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 <vcl/virdev.hxx>
+
+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: */