tdf#156230: Drop freshly unused PrinterJob and PrinterGfx
Change-Id: I5149fb447e76044e7f4bfdd9a79ee3b454859375
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/155065
Tested-by: Jenkins
Reviewed-by: خالد حسني <khaled@libreoffice.org>
diff --git a/vcl/Library_vcl.mk b/vcl/Library_vcl.mk
index 6293e292..c29801f 100644
--- a/vcl/Library_vcl.mk
+++ b/vcl/Library_vcl.mk
@@ -559,15 +559,9 @@ vcl_headless_freetype_code=\
vcl/unx/generic/fontmanager/fontconfig \
vcl/unx/generic/fontmanager/fontmanager \
vcl/unx/generic/fontmanager/helper \
vcl/unx/generic/print/bitmap_gfx \
vcl/unx/generic/print/common_gfx \
vcl/unx/generic/print/glyphset \
vcl/unx/generic/print/printerjob \
vcl/unx/generic/print/psputil \
vcl/unx/generic/print/genpspgraphics \
vcl/unx/generic/print/genprnpsp \
vcl/unx/generic/print/prtsetup \
vcl/unx/generic/print/text_gfx \
vcl/unx/generic/printer/jobdata \
vcl/unx/generic/printer/ppdparser \
diff --git a/vcl/inc/unx/printergfx.hxx b/vcl/inc/unx/printergfx.hxx
deleted file mode 100644
index 0c89ef4..0000000
--- a/vcl/inc/unx/printergfx.hxx
+++ /dev/null
@@ -1,346 +0,0 @@
/* -*- 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_VCL_INC_GENERIC_PRINTERGFX_HXX
#define INCLUDED_VCL_INC_GENERIC_PRINTERGFX_HXX
#include <osl/file.hxx>
#include <tools/gen.hxx>
#include <vcl/dllapi.h>
#include <impglyphitem.hxx>
#include <list>
#include <vector>
enum class PolyFlags : sal_uInt8;
namespace psp {
struct JobData;
/*
* lightweight container to handle RGB values
*/
class PrinterColor
{
public:
enum class ColorSpace { eInvalid, eRGB };
private:
sal_uInt8 mnRed;
sal_uInt8 mnGreen;
sal_uInt8 mnBlue;
ColorSpace meColorspace;
public:
PrinterColor()
: mnRed(0)
, mnGreen(0)
, mnBlue(0)
, meColorspace(ColorSpace::eInvalid)
{}
PrinterColor (sal_uInt16 nRed, sal_uInt16 nGreen,
sal_uInt16 nBlue) :
mnRed (nRed),
mnGreen (nGreen),
mnBlue (nBlue),
meColorspace (ColorSpace::eRGB)
{}
PrinterColor (sal_uInt32 nRGB) :
mnRed ((nRGB & 0x00ff0000) >> 16),
mnGreen ((nRGB & 0x0000ff00) >> 8),
mnBlue ((nRGB & 0x000000ff) ),
meColorspace (ColorSpace::eRGB)
{}
bool Is () const
{ return meColorspace != ColorSpace::eInvalid; }
sal_uInt16 GetRed () const
{ return mnRed; }
sal_uInt16 GetGreen () const
{ return mnGreen; }
sal_uInt16 GetBlue () const
{ return mnBlue; }
bool operator== (const PrinterColor& aColor) const
{
return aColor.Is() && Is()
&& mnRed == aColor.mnRed
&& mnGreen == aColor.mnGreen
&& mnBlue == aColor.mnBlue;
}
bool operator!= (const PrinterColor& aColor) const
{ return ! (aColor==*this); }
PrinterColor& operator= (sal_uInt32 nRGB)
{
meColorspace = ColorSpace::eRGB;
mnBlue = (nRGB & 0x000000ff);
mnGreen = (nRGB & 0x0000ff00) >> 8;
mnRed = (nRGB & 0x00ff0000) >> 16;
return *this;
}
};
class GlyphSet;
class PrinterJob;
class PrintFontManager;
struct CharacterMetric;
/*
* Bitmap Interface, this has to be filled with your actual bitmap implementation
* sample implementations can be found in:
* psprint/workben/cui/pspdem.cxx
* vcl/unx/source/gdi/salgdi2.cxx
*/
class PrinterBmp
{
public:
virtual ~PrinterBmp () = 0;
virtual sal_uInt32 GetPaletteColor (sal_uInt32 nIdx) const = 0;
virtual sal_uInt32 GetPaletteEntryCount () const = 0;
virtual sal_uInt32 GetPixelRGB (sal_uInt32 nRow, sal_uInt32 nColumn) const = 0;
virtual sal_uInt8 GetPixelGray (sal_uInt32 nRow, sal_uInt32 nColumn) const = 0;
virtual sal_uInt8 GetPixelIdx (sal_uInt32 nRow, sal_uInt32 nColumn) const = 0;
virtual sal_uInt32 GetDepth () const = 0;
};
enum class ImageType {
TrueColorImage,
MonochromeImage,
PaletteImage,
GrayScaleImage
};
/*
* printer raster operations
*/
struct GraphicsStatus
{
OString maFont;
rtl_TextEncoding maEncoding;
bool mbArtItalic;
bool mbArtBold;
sal_Int32 mnTextHeight;
sal_Int32 mnTextWidth;
PrinterColor maColor;
double mfLineWidth;
GraphicsStatus();
};
class PrinterGfx
{
private:
/* common settings */
double mfScaleX;
double mfScaleY;
sal_uInt32 mnDpi;
sal_uInt16 mnDepth;
sal_uInt16 mnPSLevel;
bool mbColor;
bool mbUploadPS42Fonts;
osl::File* mpPageBody;
/* text/font related data, for a type1 font it has to be checked
whether this font has already been downloaded. A TrueType font
will be converted into one or more Type3 fonts, containing glyphs
in no particular order. In addition to the existence of the
glyph in one of the subfonts, the mapping from unicode to the
glyph has to be remembered */
std::vector< GlyphSet > maPS3Font;
sal_Int32 mnFontID;
Degree10 mnTextAngle;
bool mbTextVertical;
PrintFontManager& mrFontMgr;
/* bitmap drawing implementation */
void DrawPS1GrayImage (const PrinterBmp& rBitmap, const tools::Rectangle& rArea);
void writePS2ImageHeader (const tools::Rectangle& rArea, psp::ImageType nType);
void writePS2Colorspace (const PrinterBmp& rBitmap, psp::ImageType nType);
void DrawPS2GrayImage (const PrinterBmp& rBitmap, const tools::Rectangle& rArea);
void DrawPS2PaletteImage (const PrinterBmp& rBitmap, const tools::Rectangle& rArea);
void DrawPS2TrueColorImage (const PrinterBmp& rBitmap, const tools::Rectangle& rArea);
void DrawPS2MonoImage (const PrinterBmp& rBitmap, const tools::Rectangle& rArea);
/* clip region */
std::list< tools::Rectangle > maClipRegion;
bool JoinVerticalClipRectangles( std::list< tools::Rectangle >::iterator& it,
Point& aOldPoint, sal_Int32& nColumn );
/* color settings */
PrinterColor maFillColor;
PrinterColor maTextColor;
PrinterColor maLineColor;
/* graphics state */
GraphicsStatus maVirtualStatus;
std::list< GraphicsStatus > maGraphicsStack;
GraphicsStatus& currentState() { return maGraphicsStack.front(); }
public:
/* graphics status update */
void PSSetColor ();
void PSSetLineWidth ();
void PSSetFont ();
/* graphics status functions */
void PSSetColor (const PrinterColor& rColor)
{ maVirtualStatus.maColor = rColor; }
void PSSetFont (const OString& rName,
rtl_TextEncoding nEncoding)
{ maVirtualStatus.maFont = rName; maVirtualStatus.maEncoding = nEncoding; }
/* graphics status stack */
void PSGSave ();
void PSGRestore ();
/* PS helpers */
enum pspath_t { moveto = 0, lineto = 1 };
void PSBinLineTo (const Point& rCurrent, Point& rOld,
sal_Int32& nColumn);
void PSBinMoveTo (const Point& rCurrent, Point& rOld,
sal_Int32& nColumn);
void PSBinStartPath ();
void PSBinEndPath ();
void PSBinCurrentPath (sal_uInt32 nPoints, const Point* pPath);
void PSBinPath (const Point& rCurrent, Point& rOld,
pspath_t eType, sal_Int32& nColumn);
void PSRotate (Degree10 nAngle);
void PSTranslate (const Point& rPoint);
void PSMoveTo (const Point& rPoint);
void PSScale (double fScaleX, double fScaleY);
void PSLineTo(const Point& rPoint );
void PSPointOp (const Point& rPoint, const char* pOperator);
void PSHexString (const unsigned char* pString, sal_Int16 nLen);
void PSShowGlyph (const unsigned char nGlyphId);
void OnEndJob ();
void writeResources( osl::File* pFile, std::vector< OString >& rSuppliedFonts );
PrintFontManager& GetFontMgr () { return mrFontMgr; }
void drawGlyph(const Point& rPoint,
sal_GlyphId aGlyphId);
public:
PrinterGfx();
~PrinterGfx();
void Init (PrinterJob &rPrinterSpec);
void Init (const JobData& rData);
void Clear();
// query depth
sal_uInt16 GetBitCount () const { return mnDepth;}
// clip region
void ResetClipRegion ();
void BeginSetClipRegion();
void UnionClipRegion (sal_Int32 nX, sal_Int32 nY,
sal_Int32 nDX, sal_Int32 nDY);
void EndSetClipRegion ();
// set xy color
void SetLineColor (const PrinterColor& rLineColor = PrinterColor())
{ maLineColor = rLineColor; }
void SetFillColor (const PrinterColor& rFillColor = PrinterColor())
{ maFillColor = rFillColor; }
// drawing primitives
void DrawPixel (const Point& rPoint, const PrinterColor& rPixelColor);
void DrawPixel (const Point& rPoint)
{ DrawPixel (rPoint, maLineColor); }
void DrawLine (const Point& rFrom, const Point& rTo);
void DrawRect (const tools::Rectangle& rRectangle);
void DrawPolyLine (sal_uInt32 nPoints, const Point* pPath );
void DrawPolygon (sal_uInt32 nPoints, const Point* pPath);
void DrawPolyPolygon (sal_uInt32 nPoly,
const sal_uInt32 *pPolygonSize,
const Point** pPolygonList);
void DrawPolyLineBezier (sal_uInt32 nPoints,
const Point* pPath,
const PolyFlags* pFlgAry );
void DrawPolygonBezier (sal_uInt32 nPoints,
const Point* pPath,
const PolyFlags* pFlgAry);
void DrawPolyPolygonBezier (sal_uInt32 nPoly,
const sal_uInt32* pPoints,
const Point* const* pPtAry,
const PolyFlags* const* pFlgAry);
// eps
bool DrawEPS ( const tools::Rectangle& rBoundingBox, void* pPtr, sal_uInt32 nSize);
// image drawing
void DrawBitmap (const tools::Rectangle& rDest, const tools::Rectangle& rSrc,
const PrinterBmp& rBitmap);
// font and text handling
void SetFont (
sal_Int32 nFontID,
sal_Int32 nPointHeight,
sal_Int32 nPointWidth,
Degree10 nAngle,
bool bVertical,
bool bArtItalic,
bool bArtBold
);
sal_Int32 GetFontID () const
{ return mnFontID; }
bool GetFontVertical() const
{ return mbTextVertical; }
sal_Int32 GetFontHeight () const
{ return maVirtualStatus.mnTextHeight; }
sal_Int32 GetFontWidth () const
{ return maVirtualStatus.mnTextWidth; }
bool GetArtificialItalic() const
{ return maVirtualStatus.mbArtItalic; }
bool GetArtificialBold() const
{ return maVirtualStatus.mbArtBold; }
void SetTextColor (PrinterColor const & rTextColor)
{ maTextColor = rTextColor; }
void DrawGlyph(const Point& rPoint,
const GlyphItem& rGlyph);
};
} /* namespace psp */
#endif // INCLUDED_VCL_INC_GENERIC_PRINTERGFX_HXX
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/inc/unx/printerjob.hxx b/vcl/inc/unx/printerjob.hxx
deleted file mode 100644
index 47d1c0a..0000000
--- a/vcl/inc/unx/printerjob.hxx
+++ /dev/null
@@ -1,129 +0,0 @@
/* -*- 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_VCL_INC_GENERIC_PRINTERJOB_HXX
#define INCLUDED_VCL_INC_GENERIC_PRINTERJOB_HXX
#include <jobdata.hxx>
#include <osl/file.hxx>
#include <string_view>
#include <vector>
namespace psp {
class PrinterGfx;
class PrinterJob
{
private:
OUString maSpoolDirName;
OUString maFileName; // empty: spool to command, else spool to named file
OUString maJobTitle;
int mnFileMode;
std::unique_ptr<osl::File> mpJobHeader;
std::unique_ptr<osl::File> mpJobTrailer;
std::vector< std::unique_ptr<osl::File> > maPageVector;
std::vector< std::unique_ptr<osl::File> > maHeaderVector;
JobData m_aDocumentJobData;
JobData m_aLastJobData;
PrinterGfx* m_pGraphics;
sal_uInt32 mnResolution;
sal_uInt32 mnWidthPt;
sal_uInt32 mnHeightPt;
sal_uInt32 mnMaxWidthPt;
sal_uInt32 mnMaxHeightPt;
int mnLandscapes;
int mnPortraits;
sal_uInt32 mnLMarginPt;
sal_uInt32 mnRMarginPt;
sal_uInt32 mnTMarginPt;
sal_uInt32 mnBMarginPt;
double mfXScale;
double mfYScale;
bool m_bQuickJob;
private:
std::unique_ptr<osl::File> CreateSpoolFile (std::u16string_view rName,
std::u16string_view rExtension) const;
void InitPaperSize (const JobData& rJobSetup);
bool writeFeatureList( osl::File* pFile, const JobData&, bool bDocumentSetup ) const;
bool writeSetup( osl::File* pFile, const JobData& );
bool writePageSetup( osl::File* pFile, const JobData&, bool bWriteFeatures );
static void writeJobPatch( osl::File* File, const JobData& );
static void writeProlog (osl::File* pFile, const JobData& );
public: // for usage in PrinterGfx
sal_uInt32 GetResolution () const { return mnResolution; }
void GetScale (double &rXScale, double &rYScale) const;
sal_uInt16 GetDepth () const;
sal_uInt16 GetPostscriptLevel (const JobData *pJobData = nullptr) const;
bool IsColorPrinter () const;
osl::File* GetCurrentPageBody ();
const OUString& GetPrinterName() const { return m_aLastJobData.m_aPrinterName; }
public:
PrinterJob ();
~PrinterJob ();
/* rFileName: if length is greater than 0 save resulting PostScript
* to named file.
* nMode: only meaningful when saving to file: if nonzero, try
* to impose the mode on the resulting file's inode; for nonexistent
* files use open, for existent files try a chmod
* rJobName: text to appear in the %%Title comment
* rAppName: text to appear in the %%Creator comment
* rSetupData: JobData that apply to this job
* pGraphics: the graphics used to print this job;
* this graphics must live until EndJob() has returned
* bIsQuickJob: the job was started as "direct print" meaning
* the quick command for spooling should be used instead
* of the normal command
*/
bool StartJob (const OUString& rFileName,
int nMode,
const OUString& rJobName,
std::u16string_view rAppName,
const JobData& rSetupData,
PrinterGfx* pGraphics,
bool bIsQuickJob
);
bool EndJob ();
void StartPage (const JobData& rJobSetup);
void EndPage ();
};
} // namespace psp
#endif // INCLUDED_VCL_INC_GENERIC_PRINTERJOB_HXX
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/print/bitmap_gfx.cxx b/vcl/unx/generic/print/bitmap_gfx.cxx
deleted file mode 100644
index 2d86497..0000000
--- a/vcl/unx/generic/print/bitmap_gfx.cxx
+++ /dev/null
@@ -1,674 +0,0 @@
/* -*- 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 <array>
#include <memory>
#include "psputil.hxx"
#include <unx/printergfx.hxx>
namespace psp {
const sal_uInt32 nLineLength = 80;
const sal_uInt32 nBufferSize = 16384;
/*
*
* Bitmap compression / Hex encoding / Ascii85 Encoding
*
*/
PrinterBmp::~PrinterBmp()
{
}
/* HexEncoder */
namespace {
class HexEncoder
{
private:
osl::File* mpFile;
sal_uInt32 mnColumn;
sal_uInt32 mnOffset;
OStringBuffer mpFileBuffer;
public:
explicit HexEncoder (osl::File* pFile);
~HexEncoder ();
void WriteAscii (sal_uInt8 nByte);
void EncodeByte (sal_uInt8 nByte);
void FlushLine ();
};
}
HexEncoder::HexEncoder (osl::File* pFile) :
mpFile (pFile),
mnColumn (0),
mnOffset (0)
{}
HexEncoder::~HexEncoder ()
{
FlushLine ();
if (mnColumn > 0)
WritePS (mpFile, "\n");
}
void
HexEncoder::WriteAscii (sal_uInt8 nByte)
{
sal_uInt32 nOff = psp::getHexValueOf (nByte, mpFileBuffer);
mnColumn += nOff;
mnOffset += nOff;
if (mnColumn >= nLineLength)
{
mnOffset += psp::appendStr ("\n", mpFileBuffer);
mnColumn = 0;
}
if (mnOffset >= nBufferSize)
FlushLine ();
}
void
HexEncoder::EncodeByte (sal_uInt8 nByte)
{
WriteAscii (nByte);
}
void
HexEncoder::FlushLine ()
{
if (mnOffset > 0)
{
WritePS (mpFile, mpFileBuffer.makeStringAndClear());
mnOffset = 0;
}
}
/* Ascii85 encoder, is abi compatible with HexEncoder but writes a ~> to
indicate end of data EOD */
namespace {
class Ascii85Encoder
{
private:
osl::File* mpFile;
sal_uInt32 mnByte;
sal_uInt8 mpByteBuffer[4];
sal_uInt32 mnColumn;
sal_uInt32 mnOffset;
OStringBuffer mpFileBuffer;
inline void PutByte (sal_uInt8 nByte);
inline void PutEOD ();
void ConvertToAscii85 ();
void FlushLine ();
public:
explicit Ascii85Encoder (osl::File* pFile);
virtual ~Ascii85Encoder ();
virtual void EncodeByte (sal_uInt8 nByte);
void WriteAscii (sal_uInt8 nByte);
};
}
Ascii85Encoder::Ascii85Encoder (osl::File* pFile) :
mpFile (pFile),
mnByte (0),
mnColumn (0),
mnOffset (0)
{}
inline void
Ascii85Encoder::PutByte (sal_uInt8 nByte)
{
mpByteBuffer [mnByte++] = nByte;
}
inline void
Ascii85Encoder::PutEOD ()
{
WritePS (mpFile, "~>\n");
}
void
Ascii85Encoder::ConvertToAscii85 ()
{
// Add (4 - mnByte) zero padding bytes:
if (mnByte < 4)
std::memset (mpByteBuffer + mnByte, 0, (4 - mnByte) * sizeof(sal_uInt8));
sal_uInt32 nByteValue = mpByteBuffer[0] * 256 * 256 * 256
+ mpByteBuffer[1] * 256 * 256
+ mpByteBuffer[2] * 256
+ mpByteBuffer[3];
if (nByteValue == 0 && mnByte == 4)
{
/* special case of 4 Bytes in row */
mpFileBuffer.append('z');
mnOffset += 1;
mnColumn += 1;
}
else
{
/* real ascii85 encoding */
// Of the up to 5 characters to be generated, do not generate the last (4 - mnByte) ones
// that correspond to the (4 - mnByte) zero padding bytes added to the input:
auto const pos = mpFileBuffer.getLength();
if (mnByte == 4) {
mpFileBuffer.insert(pos, char((nByteValue % 85) + 33));
}
nByteValue /= 85;
if (mnByte >= 3) {
mpFileBuffer.insert(pos, char((nByteValue % 85) + 33));
}
nByteValue /= 85;
if (mnByte >= 2) {
mpFileBuffer.insert(pos, char((nByteValue % 85) + 33));
}
nByteValue /= 85;
mpFileBuffer.insert(pos, char((nByteValue % 85) + 33));
nByteValue /= 85;
mpFileBuffer.insert(pos, char((nByteValue % 85) + 33));
mnColumn += (mnByte + 1);
mnOffset += (mnByte + 1);
/* insert a newline if necessary */
if (mnColumn > nLineLength)
{
sal_uInt32 nEolOff = mnColumn - nLineLength;
auto const posNl = pos + (mnByte + 1) - nEolOff;
mpFileBuffer.insert(posNl, '\n');
mnOffset++;
mnColumn = nEolOff;
}
}
mnByte = 0;
}
void
Ascii85Encoder::WriteAscii (sal_uInt8 nByte)
{
PutByte (nByte);
if (mnByte == 4)
ConvertToAscii85 ();
if (mnColumn >= nLineLength)
{
mnOffset += psp::appendStr ("\n", mpFileBuffer);
mnColumn = 0;
}
if (mnOffset >= nBufferSize)
FlushLine ();
}
void
Ascii85Encoder::EncodeByte (sal_uInt8 nByte)
{
WriteAscii (nByte);
}
void
Ascii85Encoder::FlushLine ()
{
if (mnOffset > 0)
{
WritePS (mpFile, mpFileBuffer.makeStringAndClear());
mnOffset = 0;
}
}
Ascii85Encoder::~Ascii85Encoder ()
{
if (mnByte > 0)
ConvertToAscii85 ();
if (mnOffset > 0)
FlushLine ();
PutEOD ();
}
/* LZW encoder */
namespace {
class LZWEncoder : public Ascii85Encoder
{
private:
struct LZWCTreeNode
{
LZWCTreeNode* mpBrother; // next node with same parent
LZWCTreeNode* mpFirstChild; // first son
sal_uInt16 mnCode; // code for the string
sal_uInt16 mnValue; // pixelvalue
};
std::array<LZWCTreeNode, 4096>
maTable; // LZW compression data
LZWCTreeNode* mpPrefix; // the compression is as same as the TIFF compression
static constexpr sal_uInt16 gnDataSize = 8;
static constexpr sal_uInt16 gnClearCode = 1 << gnDataSize;
static constexpr sal_uInt16 gnEOICode = gnClearCode + 1;
sal_uInt16 mnTableSize;
sal_uInt16 mnCodeSize;
sal_uInt32 mnOffset;
sal_uInt32 mdwShift;
void WriteBits (sal_uInt16 nCode, sal_uInt16 nCodeLen);
public:
explicit LZWEncoder (osl::File* pOutputFile);
virtual ~LZWEncoder () override;
virtual void EncodeByte (sal_uInt8 nByte) override;
};
}
LZWEncoder::LZWEncoder(osl::File* pOutputFile) :
Ascii85Encoder (pOutputFile),
maTable{{}},
mpPrefix(nullptr),
mnTableSize(gnEOICode + 1),
mnCodeSize(gnDataSize + 1),
mnOffset(32), // free bits in dwShift
mdwShift(0)
{
for (sal_uInt32 i = 0; i < 4096; i++)
{
maTable[i].mpBrother = nullptr;
maTable[i].mpFirstChild = nullptr;
maTable[i].mnCode = i;
maTable[i].mnValue = static_cast<sal_uInt8>(maTable[i].mnCode);
}
WriteBits( gnClearCode, mnCodeSize );
}
LZWEncoder::~LZWEncoder()
{
if (mpPrefix)
WriteBits (mpPrefix->mnCode, mnCodeSize);
WriteBits (gnEOICode, mnCodeSize);
}
void
LZWEncoder::WriteBits (sal_uInt16 nCode, sal_uInt16 nCodeLen)
{
mdwShift |= (nCode << (mnOffset - nCodeLen));
mnOffset -= nCodeLen;
while (mnOffset < 24)
{
WriteAscii (static_cast<sal_uInt8>(mdwShift >> 24));
mdwShift <<= 8;
mnOffset += 8;
}
if (nCode == 257 && mnOffset != 32)
WriteAscii (static_cast<sal_uInt8>(mdwShift >> 24));
}
void
LZWEncoder::EncodeByte (sal_uInt8 nByte )
{
LZWCTreeNode* p;
sal_uInt16 i;
sal_uInt8 nV;
if (!mpPrefix)
{
mpPrefix = maTable.data() + nByte;
}
else
{
nV = nByte;
for (p = mpPrefix->mpFirstChild; p != nullptr; p = p->mpBrother)
{
if (p->mnValue == nV)
break;
}
if (p != nullptr)
{
mpPrefix = p;
}
else
{
WriteBits (mpPrefix->mnCode, mnCodeSize);
if (mnTableSize == 409)
{
WriteBits (gnClearCode, mnCodeSize);
for (i = 0; i < gnClearCode; i++)
maTable[i].mpFirstChild = nullptr;
mnCodeSize = gnDataSize + 1;
mnTableSize = gnEOICode + 1;
}
else
{
if(mnTableSize == static_cast<sal_uInt16>((1 << mnCodeSize) - 1))
mnCodeSize++;
p = maTable.data() + (mnTableSize++);
p->mpBrother = mpPrefix->mpFirstChild;
mpPrefix->mpFirstChild = p;
p->mnValue = nV;
p->mpFirstChild = nullptr;
}
mpPrefix = maTable.data() + nV;
}
}
}
/*
*
* bitmap handling routines
*
*/
void
PrinterGfx::DrawBitmap (const tools::Rectangle& rDest, const tools::Rectangle& rSrc,
const PrinterBmp& rBitmap)
{
double fScaleX = static_cast<double>(rDest.GetWidth());
double fScaleY = static_cast<double>(rDest.GetHeight());
if(rSrc.GetWidth() > 0)
{
fScaleX = static_cast<double>(rDest.GetWidth()) / static_cast<double>(rSrc.GetWidth());
}
if(rSrc.GetHeight() > 0)
{
fScaleY = static_cast<double>(rDest.GetHeight()) / static_cast<double>(rSrc.GetHeight());
}
PSGSave ();
PSTranslate (rDest.BottomLeft());
PSScale (fScaleX, fScaleY);
if (mnPSLevel >= 2)
{
if (rBitmap.GetDepth() == 1)
{
DrawPS2MonoImage (rBitmap, rSrc);
}
else
if (rBitmap.GetDepth() == 8 && mbColor)
{
// if the palette is larger than the image itself print it as a truecolor
// image to save diskspace. This is important for printing transparent
// bitmaps that are disassembled into small pieces
sal_Int32 nImageSz = rSrc.GetWidth() * rSrc.GetHeight();
sal_Int32 nPaletteSz = rBitmap.GetPaletteEntryCount();
if ((nImageSz < nPaletteSz) || (nImageSz < 24) )
DrawPS2TrueColorImage (rBitmap, rSrc);
else
DrawPS2PaletteImage (rBitmap, rSrc);
}
else
if (rBitmap.GetDepth() == 24 && mbColor)
{
DrawPS2TrueColorImage (rBitmap, rSrc);
}
else
{
DrawPS2GrayImage (rBitmap, rSrc);
}
}
else
{
DrawPS1GrayImage (rBitmap, rSrc);
}
PSGRestore ();
}
/*
*
* Implementation: PS Level 1
*
*/
void
PrinterGfx::DrawPS1GrayImage (const PrinterBmp& rBitmap, const tools::Rectangle& rArea)
{
sal_uInt32 nWidth = rArea.GetWidth();
sal_uInt32 nHeight = rArea.GetHeight();
OStringBuffer pGrayImage;
// image header
psp::getValueOf (nWidth, pGrayImage);
psp::appendStr (" ", pGrayImage);
psp::getValueOf (nHeight, pGrayImage);
psp::appendStr (" 8 ", pGrayImage);
psp::appendStr ("[ 1 0 0 1 0 ", pGrayImage);
psp::getValueOf (nHeight, pGrayImage);
psp::appendStr ("]", pGrayImage);
psp::appendStr (" {currentfile ", pGrayImage);
psp::getValueOf (nWidth, pGrayImage);
psp::appendStr (" string readhexstring pop}\n", pGrayImage);
psp::appendStr ("image\n", pGrayImage);
WritePS (mpPageBody, pGrayImage.makeStringAndClear());
// image body
HexEncoder aEncoder(mpPageBody);
for (tools::Long nRow = rArea.Top(); nRow <= rArea.Bottom(); nRow++)
{
for (tools::Long nColumn = rArea.Left(); nColumn <= rArea.Right(); nColumn++)
{
unsigned char nByte = rBitmap.GetPixelGray (nRow, nColumn);
aEncoder.EncodeByte (nByte);
}
}
WritePS (mpPageBody, "\n");
}
/*
*
* Implementation: PS Level 2
*
*/
void
PrinterGfx::writePS2ImageHeader (const tools::Rectangle& rArea, psp::ImageType nType)
{
OStringBuffer pImage;
sal_Int32 nDictType = 0;
switch (nType)
{
case psp::ImageType::TrueColorImage: nDictType = 0; break;
case psp::ImageType::PaletteImage: nDictType = 1; break;
case psp::ImageType::GrayScaleImage: nDictType = 2; break;
case psp::ImageType::MonochromeImage: nDictType = 3; break;
default: break;
}
psp::getValueOf (rArea.GetWidth(), pImage);
psp::appendStr (" ", pImage);
psp::getValueOf (rArea.GetHeight(), pImage);
psp::appendStr (" ", pImage);
psp::getValueOf (nDictType, pImage);
psp::appendStr (" ", pImage);
psp::getValueOf (sal_Int32(1), pImage); // nCompressType
psp::appendStr (" psp_imagedict image\n", pImage);
WritePS (mpPageBody, pImage.makeStringAndClear());
}
void
PrinterGfx::writePS2Colorspace(const PrinterBmp& rBitmap, psp::ImageType nType)
{
switch (nType)
{
case psp::ImageType::GrayScaleImage:
WritePS (mpPageBody, "/DeviceGray setcolorspace\n");
break;
case psp::ImageType::TrueColorImage:
WritePS (mpPageBody, "/DeviceRGB setcolorspace\n");
break;
case psp::ImageType::MonochromeImage:
case psp::ImageType::PaletteImage:
{
OStringBuffer pImage;
const sal_uInt32 nSize = rBitmap.GetPaletteEntryCount();
psp::appendStr ("[/Indexed /DeviceRGB ", pImage);
psp::getValueOf (nSize - 1, pImage);
psp::appendStr ("\npsp_lzwstring\n", pImage);
WritePS (mpPageBody, pImage.makeStringAndClear());
LZWEncoder aEncoder(mpPageBody);
for (sal_uInt32 i = 0; i < nSize; i++)
{
PrinterColor aColor = rBitmap.GetPaletteColor(i);
aEncoder.EncodeByte (aColor.GetRed());
aEncoder.EncodeByte (aColor.GetGreen());
aEncoder.EncodeByte (aColor.GetBlue());
}
WritePS (mpPageBody, "pop ] setcolorspace\n");
}
break;
default: break;
}
}
void
PrinterGfx::DrawPS2GrayImage (const PrinterBmp& rBitmap, const tools::Rectangle& rArea)
{
writePS2Colorspace(rBitmap, psp::ImageType::GrayScaleImage);
writePS2ImageHeader(rArea, psp::ImageType::GrayScaleImage);
LZWEncoder aEncoder(mpPageBody);
for (tools::Long nRow = rArea.Top(); nRow <= rArea.Bottom(); nRow++)
{
for (tools::Long nColumn = rArea.Left(); nColumn <= rArea.Right(); nColumn++)
{
unsigned char nByte = rBitmap.GetPixelGray (nRow, nColumn);
aEncoder.EncodeByte (nByte);
}
}
}
void
PrinterGfx::DrawPS2MonoImage (const PrinterBmp& rBitmap, const tools::Rectangle& rArea)
{
writePS2Colorspace(rBitmap, psp::ImageType::MonochromeImage);
writePS2ImageHeader(rArea, psp::ImageType::MonochromeImage);
LZWEncoder aEncoder(mpPageBody);
for (tools::Long nRow = rArea.Top(); nRow <= rArea.Bottom(); nRow++)
{
tools::Long nBitPos = 0;
unsigned char nByte = 0;
for (tools::Long nColumn = rArea.Left(); nColumn <= rArea.Right(); nColumn++)
{
unsigned char nBit = rBitmap.GetPixelIdx (nRow, nColumn);
nByte |= nBit << (7 - nBitPos);
if (++nBitPos == 8)
{
aEncoder.EncodeByte (nByte);
nBitPos = 0;
nByte = 0;
}
}
// keep the row byte aligned
if (nBitPos != 0)
aEncoder.EncodeByte (nByte);
}
}
void
PrinterGfx::DrawPS2PaletteImage (const PrinterBmp& rBitmap, const tools::Rectangle& rArea)
{
writePS2Colorspace(rBitmap, psp::ImageType::PaletteImage);
writePS2ImageHeader(rArea, psp::ImageType::PaletteImage);
LZWEncoder aEncoder(mpPageBody);
for (tools::Long nRow = rArea.Top(); nRow <= rArea.Bottom(); nRow++)
{
for (tools::Long nColumn = rArea.Left(); nColumn <= rArea.Right(); nColumn++)
{
unsigned char nByte = rBitmap.GetPixelIdx (nRow, nColumn);
aEncoder.EncodeByte (nByte);
}
}
}
void
PrinterGfx::DrawPS2TrueColorImage (const PrinterBmp& rBitmap, const tools::Rectangle& rArea)
{
writePS2Colorspace(rBitmap, psp::ImageType::TrueColorImage);
writePS2ImageHeader(rArea, psp::ImageType::TrueColorImage);
LZWEncoder aEncoder(mpPageBody);
for (tools::Long nRow = rArea.Top(); nRow <= rArea.Bottom(); nRow++)
{
for (tools::Long nColumn = rArea.Left(); nColumn <= rArea.Right(); nColumn++)
{
PrinterColor aColor = rBitmap.GetPixelRGB (nRow, nColumn);
aEncoder.EncodeByte (aColor.GetRed());
aEncoder.EncodeByte (aColor.GetGreen());
aEncoder.EncodeByte (aColor.GetBlue());
}
}
}
} /* namespace psp */
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/print/common_gfx.cxx b/vcl/unx/generic/print/common_gfx.cxx
deleted file mode 100644
index aba50ec..0000000
--- a/vcl/unx/generic/print/common_gfx.cxx
+++ /dev/null
@@ -1,1152 +0,0 @@
/* -*- 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 <sal/config.h>
#include "psputil.hxx"
#include "glyphset.hxx"
#include <unx/printergfx.hxx>
#include <unx/printerjob.hxx>
#include <unx/fontmanager.hxx>
#include <strhelper.hxx>
#include <printerinfomanager.hxx>
#include <tools/color.hxx>
#include <tools/poly.hxx>
#include <tools/stream.hxx>
#include <o3tl/string_view.hxx>
using namespace psp ;
const sal_Int32 nMaxTextColumn = 80;
GraphicsStatus::GraphicsStatus() :
maEncoding(RTL_TEXTENCODING_DONTKNOW),
mbArtItalic( false ),
mbArtBold( false ),
mnTextHeight( 0 ),
mnTextWidth( 0 ),
mfLineWidth( -1 )
{
}
/*
* non graphics routines
*/
void
PrinterGfx::Init (PrinterJob &rPrinterJob)
{
mpPageBody = rPrinterJob.GetCurrentPageBody ();
mnDepth = rPrinterJob.GetDepth ();
mnPSLevel = rPrinterJob.GetPostscriptLevel ();
mbColor = rPrinterJob.IsColorPrinter ();
mnDpi = rPrinterJob.GetResolution();
rPrinterJob.GetScale (mfScaleX, mfScaleY);
const PrinterInfo& rInfo( PrinterInfoManager::get().getPrinterInfo( rPrinterJob.GetPrinterName() ) );
mbUploadPS42Fonts = rInfo.m_pParser && rInfo.m_pParser->isType42Capable();
}
void
PrinterGfx::Init (const JobData& rData)
{
mpPageBody = nullptr;
mnDepth = rData.m_nColorDepth;
mnPSLevel = rData.m_nPSLevel ? rData.m_nPSLevel : (rData.m_pParser ? rData.m_pParser->getLanguageLevel() : 2 );
mbColor = rData.m_nColorDevice ? ( rData.m_nColorDevice != -1 ) : ( rData.m_pParser == nullptr || rData.m_pParser->isColorDevice() );
int nRes = rData.m_aContext.getRenderResolution();
mnDpi = nRes;
mfScaleX = 72.0 / static_cast<double>(mnDpi);
mfScaleY = 72.0 / static_cast<double>(mnDpi);
const PrinterInfo& rInfo( PrinterInfoManager::get().getPrinterInfo( rData.m_aPrinterName ) );
mbUploadPS42Fonts = rInfo.m_pParser && rInfo.m_pParser->isType42Capable();
}
PrinterGfx::PrinterGfx()
: mfScaleX(0.0)
, mfScaleY(0.0)
, mnDpi(0)
, mnDepth(0)
, mnPSLevel(0)
, mbColor(false)
, mbUploadPS42Fonts(false)
, mpPageBody(nullptr)
, mnFontID(0)
, mnTextAngle(0)
, mbTextVertical(false)
, mrFontMgr(PrintFontManager::get())
, maFillColor(0xff,0,0)
, maTextColor(0,0,0)
, maLineColor(0, 0xff, 0)
{
maVirtualStatus.mfLineWidth = 1.0;
maVirtualStatus.mnTextHeight = 12;
maVirtualStatus.mnTextWidth = 0;
maGraphicsStack.emplace_back( );
}
PrinterGfx::~PrinterGfx()
{
}
void
PrinterGfx::Clear()
{
mpPageBody = nullptr;
mnFontID = 0;
maVirtualStatus = GraphicsStatus();
maVirtualStatus.mnTextHeight = 12;
maVirtualStatus.mnTextWidth = 0;
maVirtualStatus.mfLineWidth = 1.0;
mbTextVertical = false;
maLineColor = PrinterColor();
maFillColor = PrinterColor();
maTextColor = PrinterColor();
mnDpi = 300;
mnDepth = 24;
mnPSLevel = 2;
mbColor = true;
mnTextAngle = 0_deg10;
maClipRegion.clear();
maGraphicsStack.clear();
maGraphicsStack.emplace_back( );
}
/*
* clip region handling
*/
void
PrinterGfx::ResetClipRegion()
{
maClipRegion.clear();
PSGRestore ();
PSGSave (); // get "clean" clippath
}
void
PrinterGfx::BeginSetClipRegion()
{
maClipRegion.clear();
}
void
PrinterGfx::UnionClipRegion (sal_Int32 nX,sal_Int32 nY,sal_Int32 nDX,sal_Int32 nDY)
{
if( nDX && nDY )
maClipRegion.emplace_back(Point(nX,nY ), Size(nDX,nDY));
}
bool
PrinterGfx::JoinVerticalClipRectangles( std::list< tools::Rectangle >::iterator& it,
Point& rOldPoint, sal_Int32& rColumn )
{
bool bSuccess = false;
std::list< tools::Rectangle >::iterator tempit, nextit;
nextit = it;
++nextit;
std::list< Point > leftside, rightside;
tools::Rectangle aLastRect( *it );
leftside.emplace_back( it->Left(), it->Top() );
rightside.emplace_back( it->Right()+1, it->Top() );
while( nextit != maClipRegion.end() )
{
tempit = nextit;
++tempit;
if( nextit->Top() == aLastRect.Bottom()+1 )
{
if(
( nextit->Left() >= aLastRect.Left() && nextit->Left() <= aLastRect.Right() ) // left endpoint touches last rectangle
||
( nextit->Right() >= aLastRect.Left() && nextit->Right() <= aLastRect.Right() ) // right endpoint touches last rectangle
||
( nextit->Left() <= aLastRect.Left() && nextit->Right() >= aLastRect.Right() ) // whole line touches last rectangle
)
{
if( aLastRect.GetHeight() > 1 ||
std::abs( aLastRect.Left() - nextit->Left() ) > 2 ||
std::abs( aLastRect.Right() - nextit->Right() ) > 2
)
{
leftside.emplace_back( aLastRect.Left(), aLastRect.Bottom()+1 );
rightside.emplace_back( aLastRect.Right()+1, aLastRect.Bottom()+1 );
}
aLastRect = *nextit;
leftside.push_back( aLastRect.TopLeft() );
rightside.push_back( aLastRect.TopRight() );
maClipRegion.erase( nextit );
}
}
nextit = tempit;
}
if( leftside.size() > 1 )
{
// push the last coordinates
leftside.emplace_back( aLastRect.Left(), aLastRect.Bottom()+1 );
rightside.emplace_back( aLastRect.Right()+1, aLastRect.Bottom()+1 );
// cool, we can concatenate rectangles
const int nDX = -65536, nDY = 65536;
int nNewDX = 0, nNewDY = 0;
Point aLastPoint = leftside.front();
PSBinMoveTo (aLastPoint, rOldPoint, rColumn);
leftside.pop_front();
while( !leftside.empty() )
{
Point aPoint (leftside.front());
leftside.pop_front();
// may have been the last one
if( !leftside.empty() )
{
nNewDX = aPoint.X() - aLastPoint.X();
nNewDY = aPoint.Y() - aLastPoint.Y();
if( nNewDX != 0 &&
static_cast<double>(nNewDY)/static_cast<double>(nNewDX) == double(nDY)/double(nDX) )
continue;
}
PSBinLineTo (aPoint, rOldPoint, rColumn);
aLastPoint = aPoint;
}
aLastPoint = rightside.back();
PSBinLineTo (aLastPoint, rOldPoint, rColumn);
rightside.pop_back();
while( !rightside.empty() )
{
Point aPoint (rightside.back());
rightside.pop_back();
if( !rightside.empty() )
{
nNewDX = aPoint.X() - aLastPoint.X();
nNewDY = aPoint.Y() - aLastPoint.Y();
if( nNewDX != 0 &&
static_cast<double>(nNewDY)/static_cast<double>(nNewDX) == double(nDY)/double(nDX) )
continue;
}
PSBinLineTo (aPoint, rOldPoint, rColumn);
}
tempit = it;
++tempit;
maClipRegion.erase( it );
it = tempit;
bSuccess = true;
}
return bSuccess;
}
void
PrinterGfx::EndSetClipRegion()
{
PSGRestore ();
PSGSave (); // get "clean" clippath
PSBinStartPath ();
Point aOldPoint (0, 0);
sal_Int32 nColumn = 0;
std::list< tools::Rectangle >::iterator it = maClipRegion.begin();
while( it != maClipRegion.end() )
{
// try to concatenate adjacent rectangles
// first try in y direction, then in x direction
if( ! JoinVerticalClipRectangles( it, aOldPoint, nColumn ) )
{
// failed, so it is a single rectangle
PSBinMoveTo (Point( it->Left()-1, it->Top()-1), aOldPoint, nColumn );
PSBinLineTo (Point( it->Left()-1, it->Bottom()+1 ), aOldPoint, nColumn );
PSBinLineTo (Point( it->Right()+1, it->Bottom()+1 ), aOldPoint, nColumn );
PSBinLineTo (Point( it->Right()+1, it->Top()-1 ), aOldPoint, nColumn );
++it;
}
}
PSBinEndPath ();
WritePS (mpPageBody, "closepath clip newpath\n");
maClipRegion.clear();
}
/*
* draw graphic primitives
*/
void
PrinterGfx::DrawRect (const tools::Rectangle& rRectangle )
{
OStringBuffer pRect;
psp::getValueOf (rRectangle.Left(), pRect);
psp::appendStr (" ", pRect);
psp::getValueOf (rRectangle.Top(), pRect);
psp::appendStr (" ", pRect);
psp::getValueOf (rRectangle.GetWidth(), pRect);
psp::appendStr (" ", pRect);
psp::getValueOf (rRectangle.GetHeight(), pRect);
psp::appendStr (" ", pRect);
auto const rect = pRect.makeStringAndClear();
if( maFillColor.Is() )
{
PSSetColor (maFillColor);
PSSetColor ();
WritePS (mpPageBody, rect);
WritePS (mpPageBody, "rectfill\n");
}
if( maLineColor.Is() )
{
PSSetColor (maLineColor);
PSSetColor ();
PSSetLineWidth ();
WritePS (mpPageBody, rect);
WritePS (mpPageBody, "rectstroke\n");
}
}
void
PrinterGfx::DrawLine (const Point& rFrom, const Point& rTo)
{
if( maLineColor.Is() )
{
PSSetColor (maLineColor);
PSSetColor ();
PSSetLineWidth ();
PSMoveTo (rFrom);
PSLineTo (rTo);
WritePS (mpPageBody, "stroke\n" );
}
}
void
PrinterGfx::DrawPixel (const Point& rPoint, const PrinterColor& rPixelColor)
{
if( rPixelColor.Is() )
{
PSSetColor (rPixelColor);
PSSetColor ();
PSMoveTo (rPoint);
PSLineTo (Point (rPoint.X ()+1, rPoint.Y ()));
PSLineTo (Point (rPoint.X ()+1, rPoint.Y ()+1));
PSLineTo (Point (rPoint.X (), rPoint.Y ()+1));
WritePS (mpPageBody, "fill\n" );
}
}
void
PrinterGfx::DrawPolyLine (sal_uInt32 nPoints, const Point* pPath)
{
if( maLineColor.Is() && nPoints && pPath )
{
PSSetColor (maLineColor);
PSSetColor ();
PSSetLineWidth ();
PSBinCurrentPath (nPoints, pPath);
WritePS (mpPageBody, "stroke\n" );
}
}
void
PrinterGfx::DrawPolygon (sal_uInt32 nPoints, const Point* pPath)
{
// premature end of operation
if (nPoints <= 0 || (pPath == nullptr) || !(maFillColor.Is() || maLineColor.Is()))
return;
// setup closed path
Point aPoint( 0, 0 );
sal_Int32 nColumn( 0 );
PSBinStartPath();
PSBinMoveTo( pPath[0], aPoint, nColumn );
for( unsigned int n = 1; n < nPoints; n++ )
PSBinLineTo( pPath[n], aPoint, nColumn );
if( pPath[0] != pPath[nPoints-1] )
PSBinLineTo( pPath[0], aPoint, nColumn );
PSBinEndPath();
// fill the polygon first, then draw the border, note that fill and
// stroke reset the currentpath
// if fill and stroke, save the current path
if( maFillColor.Is() && maLineColor.Is())
PSGSave();
if (maFillColor.Is ())
{
PSSetColor (maFillColor);
PSSetColor ();
WritePS (mpPageBody, "eofill\n");
}
// restore the current path
if( maFillColor.Is() && maLineColor.Is())
PSGRestore();
if (maLineColor.Is ())
{
PSSetColor (maLineColor);
PSSetColor ();
PSSetLineWidth ();
WritePS (mpPageBody, "stroke\n");
}
}
void
PrinterGfx::DrawPolyPolygon (sal_uInt32 nPoly, const sal_uInt32* pSizes, const Point** pPaths )
{
// sanity check
if ( !nPoly || !pPaths || !(maFillColor.Is() || maLineColor.Is()))
return;
// setup closed path
for( unsigned int i = 0; i < nPoly; i++ )
{
Point aPoint( 0, 0 );
sal_Int32 nColumn( 0 );
PSBinStartPath();
PSBinMoveTo( pPaths[i][0], aPoint, nColumn );
for( unsigned int n = 1; n < pSizes[i]; n++ )
PSBinLineTo( pPaths[i][n], aPoint, nColumn );
if( pPaths[i][0] != pPaths[i][pSizes[i]-1] )
PSBinLineTo( pPaths[i][0], aPoint, nColumn );
PSBinEndPath();
}
// if eofill and stroke, save the current path
if( maFillColor.Is() && maLineColor.Is())
PSGSave();
// first draw area
if( maFillColor.Is() )
{
PSSetColor (maFillColor);
PSSetColor ();
WritePS (mpPageBody, "eofill\n");
}
// restore the current path
if( maFillColor.Is() && maLineColor.Is())
PSGRestore();
// now draw outlines
if( maLineColor.Is() )
{
PSSetColor (maLineColor);
PSSetColor ();
PSSetLineWidth ();
WritePS (mpPageBody, "stroke\n");
}
}
/*
* Bezier Polygon Drawing methods.
*/
void
PrinterGfx::DrawPolyLineBezier (sal_uInt32 nPoints, const Point* pPath, const PolyFlags* pFlgAry)
{
const sal_uInt32 nBezString= 1024;
char pString[nBezString];
if ( nPoints <= 1 || !maLineColor.Is() || !pPath )
return;
PSSetColor (maLineColor);
PSSetColor ();
PSSetLineWidth ();
snprintf(pString, nBezString, "%" SAL_PRIdINT64 " %" SAL_PRIdINT64 " moveto\n", sal_Int64(pPath[0].X()), sal_Int64(pPath[0].Y()));
WritePS(mpPageBody, pString);
// Handle the drawing of mixed lines mixed with curves
// - a normal point followed by a normal point is a line
// - a normal point followed by 2 control points and a normal point is a curve
for (unsigned int i=1; i<nPoints;)
{
if (pFlgAry[i] != PolyFlags::Control) //If the next point is a PolyFlags::Normal, we're drawing a line
{
snprintf(pString, nBezString, "%" SAL_PRIdINT64 " %" SAL_PRIdINT64 " lineto\n", sal_Int64(pPath[i].X()), sal_Int64(pPath[i].Y()));
i++;
}
else //Otherwise we're drawing a spline
{
if (i+2 >= nPoints)
return; //Error: wrong sequence of control/normal points somehow
if ((pFlgAry[i] == PolyFlags::Control) && (pFlgAry[i+1] == PolyFlags::Control) &&
(pFlgAry[i+2] != PolyFlags::Control))
{
snprintf(pString, nBezString, "%" SAL_PRIdINT64 " %" SAL_PRIdINT64 " %" SAL_PRIdINT64 " %" SAL_PRIdINT64 " %" SAL_PRIdINT64 " %" SAL_PRIdINT64 " curveto\n",
sal_Int64(pPath[i].X()), sal_Int64(pPath[i].Y()),
sal_Int64(pPath[i+1].X()), sal_Int64(pPath[i+1].Y()),
sal_Int64(pPath[i+2].X()), sal_Int64(pPath[i+2].Y()));
}
else
{
OSL_FAIL( "PrinterGfx::DrawPolyLineBezier: Strange output" );
}
i+=3;
}
WritePS(mpPageBody, pString);
}
// now draw outlines
WritePS (mpPageBody, "stroke\n");
}
void
PrinterGfx::DrawPolygonBezier (sal_uInt32 nPoints, const Point* pPath, const PolyFlags* pFlgAry)
{
const sal_uInt32 nBezString = 1024;
char pString[nBezString];
// premature end of operation
if (nPoints <= 0 || (pPath == nullptr) || !(maFillColor.Is() || maLineColor.Is()))
return;
snprintf(pString, nBezString, "%" SAL_PRIdINT64 " %" SAL_PRIdINT64 " moveto\n", sal_Int64(pPath[0].X()), sal_Int64(pPath[0].Y()));
WritePS(mpPageBody, pString); //Move to the starting point for the PolyPolygon
for (unsigned int i=1; i < nPoints;)
{
if (pFlgAry[i] != PolyFlags::Control)
{
snprintf(pString, nBezString, "%" SAL_PRIdINT64 " %" SAL_PRIdINT64 " lineto\n",
sal_Int64(pPath[i].X()), sal_Int64(pPath[i].Y()));
WritePS(mpPageBody, pString);
i++;
}
else
{
if (i+2 >= nPoints)
return; //Error: wrong sequence of control/normal points somehow
if ((pFlgAry[i] == PolyFlags::Control) && (pFlgAry[i+1] == PolyFlags::Control) &&
(pFlgAry[i+2] != PolyFlags::Control))
{
snprintf(pString, nBezString, "%" SAL_PRIdINT64 " %" SAL_PRIdINT64 " %" SAL_PRIdINT64 " %" SAL_PRIdINT64 " %" SAL_PRIdINT64 " %" SAL_PRIdINT64 " curveto\n",
sal_Int64(pPath[i].X()), sal_Int64(pPath[i].Y()),
sal_Int64(pPath[i+1].X()), sal_Int64(pPath[i+1].Y()),
sal_Int64(pPath[i+2].X()), sal_Int64(pPath[i+2].Y()));
WritePS(mpPageBody, pString);
}
else
{
OSL_FAIL( "PrinterGfx::DrawPolygonBezier: Strange output" );
}
i+=3;
}
}
// if fill and stroke, save the current path
if( maFillColor.Is() && maLineColor.Is())
PSGSave();
if (maFillColor.Is ())
{
PSSetColor (maFillColor);
PSSetColor ();
WritePS (mpPageBody, "eofill\n");
}
// restore the current path
if( maFillColor.Is() && maLineColor.Is())
PSGRestore();
}
void
PrinterGfx::DrawPolyPolygonBezier (sal_uInt32 nPoly, const sal_uInt32 * pPoints, const Point* const * pPtAry, const PolyFlags* const* pFlgAry)
{
const sal_uInt32 nBezString = 1024;
char pString[nBezString];
if ( !nPoly || !pPtAry || !pPoints || !(maFillColor.Is() || maLineColor.Is()))
return;
for (unsigned int i=0; i<nPoly;i++)
{
sal_uInt32 nPoints = pPoints[i];
// sanity check
if( nPoints == 0 || pPtAry[i] == nullptr )
continue;
snprintf(pString, nBezString, "%" SAL_PRIdINT64 " %" SAL_PRIdINT64 " moveto\n",
sal_Int64(pPtAry[i][0].X()), sal_Int64(pPtAry[i][0].Y())); //Move to the starting point
WritePS(mpPageBody, pString);
for (unsigned int j=1; j < nPoints;)
{
// if no flag array exists for this polygon, then it must be a regular
// polygon without beziers
if ( ! pFlgAry[i] || pFlgAry[i][j] != PolyFlags::Control)
{
snprintf(pString, nBezString, "%" SAL_PRIdINT64 " %" SAL_PRIdINT64 " lineto\n",
sal_Int64(pPtAry[i][j].X()), sal_Int64(pPtAry[i][j].Y()));
WritePS(mpPageBody, pString);
j++;
}
else
{
if (j+2 >= nPoints)
break; //Error: wrong sequence of control/normal points somehow
if ((pFlgAry[i][j] == PolyFlags::Control) && (pFlgAry[i][j+1] == PolyFlags::Control) && (pFlgAry[i][j+2] != PolyFlags::Control))
{
snprintf(pString, nBezString, "%" SAL_PRIdINT64 " %" SAL_PRIdINT64 " %" SAL_PRIdINT64 " %" SAL_PRIdINT64 " %" SAL_PRIdINT64 " %" SAL_PRIdINT64 " curveto\n",
sal_Int64(pPtAry[i][j].X()), sal_Int64(pPtAry[i][j].Y()),
sal_Int64(pPtAry[i][j+1].X()), sal_Int64(pPtAry[i][j+1].Y()),
sal_Int64(pPtAry[i][j+2].X()), sal_Int64(pPtAry[i][j+2].Y()));
WritePS(mpPageBody, pString);
}
else
{
OSL_FAIL( "PrinterGfx::DrawPolyPolygonBezier: Strange output" );
}
j+=3;
}
}
}
// if fill and stroke, save the current path
if( maFillColor.Is() && maLineColor.Is())
PSGSave();
if (maFillColor.Is ())
{
PSSetColor (maFillColor);
PSSetColor ();
WritePS (mpPageBody, "eofill\n");
}
// restore the current path
if( maFillColor.Is() && maLineColor.Is())
PSGRestore();
}
/*
* postscript generating routines
*/
void
PrinterGfx::PSGSave ()
{
WritePS (mpPageBody, "gsave\n" );
GraphicsStatus aNewState;
if( !maGraphicsStack.empty() )
aNewState = maGraphicsStack.front();
maGraphicsStack.push_front( aNewState );
}
void
PrinterGfx::PSGRestore ()
{
WritePS (mpPageBody, "grestore\n" );
if( maGraphicsStack.empty() )
WritePS (mpPageBody, "Error: too many grestores\n" );
else
maGraphicsStack.pop_front();
}
void
PrinterGfx::PSSetLineWidth ()
{
if( currentState().mfLineWidth != maVirtualStatus.mfLineWidth )
{
OStringBuffer pBuffer;
currentState().mfLineWidth = maVirtualStatus.mfLineWidth;
psp::getValueOfDouble (pBuffer, maVirtualStatus.mfLineWidth, 5);
psp::appendStr (" setlinewidth\n", pBuffer);
WritePS (mpPageBody, pBuffer.makeStringAndClear());
}
}
void
PrinterGfx::PSSetColor ()
{
PrinterColor& rColor( maVirtualStatus.maColor );
if( currentState().maColor == rColor )
return;
currentState().maColor = rColor;
OStringBuffer pBuffer;
if( mbColor )
{
psp::getValueOfDouble (pBuffer,
static_cast<double>(rColor.GetRed()) / 255.0, 5);
psp::appendStr (" ", pBuffer);
psp::getValueOfDouble (pBuffer,
static_cast<double>(rColor.GetGreen()) / 255.0, 5);
psp::appendStr (" ", pBuffer);
psp::getValueOfDouble (pBuffer,
static_cast<double>(rColor.GetBlue()) / 255.0, 5);
psp::appendStr (" setrgbcolor\n", pBuffer );
}
else
{
Color aColor( rColor.GetRed(), rColor.GetGreen(), rColor.GetBlue() );
sal_uInt8 nCol = aColor.GetLuminance();
psp::getValueOfDouble( pBuffer, static_cast<double>(nCol) / 255.0, 5 );
psp::appendStr( " setgray\n", pBuffer );
}
WritePS (mpPageBody, pBuffer.makeStringAndClear());
}
void
PrinterGfx::PSSetFont ()
{
GraphicsStatus& rCurrent( currentState() );
if( !(maVirtualStatus.maFont != rCurrent.maFont ||
maVirtualStatus.mnTextHeight != rCurrent.mnTextHeight ||
maVirtualStatus.maEncoding != rCurrent.maEncoding ||
maVirtualStatus.mnTextWidth != rCurrent.mnTextWidth ||
maVirtualStatus.mbArtBold != rCurrent.mbArtBold ||
maVirtualStatus.mbArtItalic != rCurrent.mbArtItalic)
)
return;
rCurrent.maFont = maVirtualStatus.maFont;
rCurrent.maEncoding = maVirtualStatus.maEncoding;
rCurrent.mnTextWidth = maVirtualStatus.mnTextWidth;
rCurrent.mnTextHeight = maVirtualStatus.mnTextHeight;
rCurrent.mbArtItalic = maVirtualStatus.mbArtItalic;
rCurrent.mbArtBold = maVirtualStatus.mbArtBold;
sal_Int32 nTextHeight = rCurrent.mnTextHeight;
sal_Int32 nTextWidth = rCurrent.mnTextWidth ? rCurrent.mnTextWidth
: rCurrent.mnTextHeight;
OStringBuffer pSetFont;
// postscript based fonts need reencoding
if ( ( rCurrent.maEncoding == RTL_TEXTENCODING_MS_1252)
|| ( rCurrent.maEncoding == RTL_TEXTENCODING_ISO_8859_1)
|| ( rCurrent.maEncoding >= RTL_TEXTENCODING_USER_START
&& rCurrent.maEncoding <= RTL_TEXTENCODING_USER_END)
)
{
OString aReencodedFont =
psp::GlyphSet::GetReencodedFontName (rCurrent.maEncoding,
rCurrent.maFont);
psp::appendStr ("(", pSetFont);
psp::appendStr (aReencodedFont.getStr(),
pSetFont);
psp::appendStr (") cvn findfont ",
pSetFont);
}
else
// tt based fonts mustn't reencode, the encoding is implied by the fontname
// same for symbol type1 fonts, don't try to touch them
{
psp::appendStr ("(", pSetFont);
psp::appendStr (rCurrent.maFont.getStr(),
pSetFont);
psp::appendStr (") cvn findfont ",
pSetFont);
}
if( ! rCurrent.mbArtItalic )
{
psp::getValueOf (nTextWidth, pSetFont);
psp::appendStr (" ", pSetFont);
psp::getValueOf (-nTextHeight, pSetFont);
psp::appendStr (" matrix scale makefont setfont\n", pSetFont);
}
else // skew 15 degrees to right
{
psp::appendStr ( " [", pSetFont);
psp::getValueOf (nTextWidth, pSetFont);
psp::appendStr (" 0 ", pSetFont);
psp::getValueOfDouble (pSetFont, 0.27*static_cast<double>(nTextWidth), 3 );
psp::appendStr ( " ", pSetFont);
psp::getValueOf (-nTextHeight, pSetFont);
psp::appendStr (" 0 0] makefont setfont\n", pSetFont);
}
WritePS (mpPageBody, pSetFont.makeStringAndClear());
}
void
PrinterGfx::PSRotate (Degree10 nAngle)
{
sal_Int32 nPostScriptAngle = -nAngle.get();
while( nPostScriptAngle < 0 )
nPostScriptAngle += 3600;
if (nPostScriptAngle == 0)
return;
sal_Int32 nFullAngle = nPostScriptAngle / 10;
sal_Int32 nTenthAngle = nPostScriptAngle % 10;
OStringBuffer pRotate;
psp::getValueOf (nFullAngle, pRotate);
psp::appendStr (".", pRotate);
psp::getValueOf (nTenthAngle, pRotate);
psp::appendStr (" rotate\n", pRotate);
WritePS (mpPageBody, pRotate.makeStringAndClear());
}
void
PrinterGfx::PSPointOp (const Point& rPoint, const char* pOperator)
{
OStringBuffer pPSCommand;
psp::getValueOf (rPoint.X(), pPSCommand);
psp::appendStr (" ", pPSCommand);
psp::getValueOf (rPoint.Y(), pPSCommand);
psp::appendStr (" ", pPSCommand);
psp::appendStr (pOperator, pPSCommand);
psp::appendStr ("\n", pPSCommand);
WritePS (mpPageBody, pPSCommand.makeStringAndClear());
}
void
PrinterGfx::PSTranslate (const Point& rPoint)
{
PSPointOp (rPoint, "translate");
}
void
PrinterGfx::PSMoveTo (const Point& rPoint)
{
PSPointOp (rPoint, "moveto");
}
void
PrinterGfx::PSLineTo (const Point& rPoint)
{
PSPointOp (rPoint, "lineto");
}
/* get a compressed representation of the path information */
#define DEBUG_BINPATH 0
void
PrinterGfx::PSBinLineTo (const Point& rCurrent, Point& rOld, sal_Int32& nColumn)
{
#if (DEBUG_BINPATH == 1)
PSLineTo (rCurrent);
#else
PSBinPath (rCurrent, rOld, lineto, nColumn);
#endif
}
void
PrinterGfx::PSBinMoveTo (const Point& rCurrent, Point& rOld, sal_Int32& nColumn)
{
#if (DEBUG_BINPATH == 1)
PSMoveTo (rCurrent);
#else
PSBinPath (rCurrent, rOld, moveto, nColumn);
#endif
}
void
PrinterGfx::PSBinStartPath ()
{
#if (DEBUG_BINPATH == 1)
WritePS (mpPageBody, "% PSBinStartPath\n");
#else
WritePS (mpPageBody, "readpath\n" );
#endif
}
void
PrinterGfx::PSBinEndPath ()
{
#if (DEBUG_BINPATH == 1)
WritePS (mpPageBody, "% PSBinEndPath\n");
#else
WritePS (mpPageBody, "~\n");
#endif
}
void
PrinterGfx::PSBinCurrentPath (sal_uInt32 nPoints, const Point* pPath)
{
// create the path
Point aPoint (0, 0);
sal_Int32 nColumn = 0;
PSBinStartPath ();
PSBinMoveTo (*pPath, aPoint, nColumn);
for (unsigned int i = 1; i < nPoints; i++)
PSBinLineTo (pPath[i], aPoint, nColumn);
PSBinEndPath ();
}
void
PrinterGfx::PSBinPath (const Point& rCurrent, Point& rOld,
pspath_t eType, sal_Int32& nColumn)
{
OStringBuffer pPath;
sal_Int32 nChar;
// create the hex representation of the dx and dy path shift, store the field
// width as it is needed for the building the command
sal_Int32 nXPrec = getAlignedHexValueOf (rCurrent.X() - rOld.X(), pPath);
sal_Int32 nYPrec = getAlignedHexValueOf (rCurrent.Y() - rOld.Y(), pPath);
// build the command, it is a char with bit representation 000cxxyy
// c represents the char, xx and yy repr. the field width of the dx and dy shift,
// dx and dy represent the number of bytes to read after the opcode
char cCmd = (eType == lineto ? char(0x00) : char(0x10));
switch (nYPrec)
{
case 2: break;
case 4: cCmd |= 0x01; break;
case 6: cCmd |= 0x02; break;
case 8: cCmd |= 0x03; break;
default: OSL_FAIL("invalid x precision in binary path");
}
switch (nXPrec)
{
case 2: break;
case 4: cCmd |= 0x04; break;
case 6: cCmd |= 0x08; break;
case 8: cCmd |= 0x0c; break;
default: OSL_FAIL("invalid y precision in binary path");
}
cCmd += 'A';
pPath.insert(0, cCmd);
auto const path = pPath.makeStringAndClear();
// write the command to file,
// line breaking at column nMaxTextColumn (80)
nChar = 1 + nXPrec + nYPrec;
if ((nColumn + nChar) > nMaxTextColumn)
{
sal_Int32 nSegment = nMaxTextColumn - nColumn;
WritePS (mpPageBody, path.copy(0, nSegment));
WritePS (mpPageBody, "\n", 1);
WritePS (mpPageBody, path.copy(nSegment));
nColumn = nChar - nSegment;
}
else
{
WritePS (mpPageBody, path);
nColumn += nChar;
}
rOld = rCurrent;
}
void
PrinterGfx::PSScale (double fScaleX, double fScaleY)
{
OStringBuffer pScale;
psp::getValueOfDouble (pScale, fScaleX, 5);
psp::appendStr (" ", pScale);
psp::getValueOfDouble (pScale, fScaleY, 5);
psp::appendStr (" scale\n", pScale);
WritePS (mpPageBody, pScale.makeStringAndClear());
}
/* psshowtext helper routines: draw an hex string for show/xshow */
void
PrinterGfx::PSHexString (const unsigned char* pString, sal_Int16 nLen)
{
OStringBuffer pHexString;
sal_Int32 nChar = psp::appendStr ("<", pHexString);
for (int i = 0; i < nLen; i++)
{
if (nChar >= (nMaxTextColumn - 1))
{
psp::appendStr ("\n", pHexString);
WritePS (mpPageBody, pHexString.makeStringAndClear());
nChar = 0;
}
nChar += psp::getHexValueOf (static_cast<sal_Int32>(pString[i]), pHexString);
}
psp::appendStr (">\n", pHexString);
WritePS (mpPageBody, pHexString.makeStringAndClear());
}
void
PrinterGfx::PSShowGlyph (const unsigned char nGlyphId)
{
PSSetColor (maTextColor);
PSSetColor ();
PSSetFont ();
// rotate the user coordinate system
if (mnTextAngle)
{
PSGSave ();
PSRotate (mnTextAngle);
}
char pBuffer[256];
if( maVirtualStatus.mbArtBold )
{
sal_Int32 nLW = maVirtualStatus.mnTextWidth;
if( nLW == 0 )
nLW = maVirtualStatus.mnTextHeight;
else
nLW = std::min(nLW, maVirtualStatus.mnTextHeight);
psp::getValueOfDouble( pBuffer, static_cast<double>(nLW) / 30.0 );
}
// dispatch to the drawing method
PSHexString (&nGlyphId, 1);
if( maVirtualStatus.mbArtBold )
{
WritePS( mpPageBody, pBuffer );
WritePS( mpPageBody, " bshow\n" );
}
else
WritePS (mpPageBody, "show\n");
// restore the user coordinate system
if (mnTextAngle)
PSGRestore ();
}
bool
PrinterGfx::DrawEPS( const tools::Rectangle& rBoundingBox, void* pPtr, sal_uInt32 nSize )
{
if( nSize == 0 )
return true;
if( ! mpPageBody )
return false;
bool bSuccess = false;
// first search the BoundingBox of the EPS data
SvMemoryStream aStream( pPtr, nSize, StreamMode::READ );
aStream.Seek( STREAM_SEEK_TO_BEGIN );
OString aLine;
OString aDocTitle;
double fLeft = 0, fRight = 0, fTop = 0, fBottom = 0;
bool bEndComments = false;
while( ! aStream.eof()
&& ( ( fLeft == 0 && fRight == 0 && fTop == 0 && fBottom == 0 ) ||
( aDocTitle.isEmpty() && !bEndComments ) )
)
{
aStream.ReadLine( aLine );
if( aLine.getLength() > 1 && aLine[0] == '%' )
{
char cChar = aLine[1];
if( cChar == '%' )
{
if( aLine.matchIgnoreAsciiCase( "%%BoundingBox:" ) )
{
aLine = WhitespaceToSpace( o3tl::getToken(aLine, 1, ':') );
if( !aLine.isEmpty() && aLine.indexOf( "atend" ) == -1 )
{
fLeft = StringToDouble( GetCommandLineToken( 0, aLine ) );
fBottom = StringToDouble( GetCommandLineToken( 1, aLine ) );
fRight = StringToDouble( GetCommandLineToken( 2, aLine ) );
fTop = StringToDouble( GetCommandLineToken( 3, aLine ) );
}
}
else if( aLine.matchIgnoreAsciiCase( "%%Title:" ) )
aDocTitle = WhitespaceToSpace( aLine.subView( 8 ) );
else if( aLine.matchIgnoreAsciiCase( "%%EndComments" ) )
bEndComments = true;
}
else if( cChar == ' ' || cChar == '\t' || cChar == '\r' || cChar == '\n' )
bEndComments = true;
}
else
bEndComments = true;
}
static sal_uInt16 nEps = 0;
if( aDocTitle.isEmpty() )
aDocTitle = OString::number(nEps++);
if( fLeft != fRight && fTop != fBottom )
{
double fScaleX = static_cast<double>(rBoundingBox.GetWidth())/(fRight-fLeft);
double fScaleY = -static_cast<double>(rBoundingBox.GetHeight())/(fTop-fBottom);
Point aTranslatePoint( static_cast<int>(rBoundingBox.Left()-fLeft*fScaleX),
static_cast<int>(rBoundingBox.Bottom()+1-fBottom*fScaleY) );
// prepare EPS
WritePS( mpPageBody,
"/b4_Inc_state save def\n"
"/dict_count countdictstack def\n"
"/op_count count 1 sub def\n"
"userdict begin\n"
"/showpage {} def\n"
"0 setgray 0 setlinecap 1 setlinewidth 0 setlinejoin\n"
"10 setmiterlimit [] 0 setdash newpath\n"
"/languagelevel where\n"
"{pop languagelevel\n"
"1 ne\n"
" {false setstrokeadjust false setoverprint\n"
" } if\n"
"}if\n" );
// set up clip path and scale
BeginSetClipRegion();
UnionClipRegion( rBoundingBox.Left(), rBoundingBox.Top(), rBoundingBox.GetWidth(), rBoundingBox.GetHeight() );
EndSetClipRegion();
PSTranslate( aTranslatePoint );
PSScale( fScaleX, fScaleY );
// DSC requires BeginDocument
WritePS( mpPageBody, "%%BeginDocument: " );
WritePS( mpPageBody, aDocTitle );
WritePS( mpPageBody, "\n" );
// write the EPS data
sal_uInt64 nOutLength;
mpPageBody->write( pPtr, nSize, nOutLength );
bSuccess = nOutLength == nSize;
// corresponding EndDocument
if( static_cast<char*>(pPtr)[ nSize-1 ] != '\n' )
WritePS( mpPageBody, "\n" );
WritePS( mpPageBody, "%%EndDocument\n" );
// clean up EPS
WritePS( mpPageBody,
"count op_count sub {pop} repeat\n"
"countdictstack dict_count sub {end} repeat\n"
"b4_Inc_state restore\n" );
}
return bSuccess;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/print/glyphset.cxx b/vcl/unx/generic/print/glyphset.cxx
deleted file mode 100644
index 283558a..0000000
--- a/vcl/unx/generic/print/glyphset.cxx
+++ /dev/null
@@ -1,297 +0,0 @@
/* -*- 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 "glyphset.hxx"
#include <sft.hxx>
#include <unx/printergfx.hxx>
#include <fontsubset.hxx>
#include <unx/fontmanager.hxx>
#include <tools/gen.hxx>
#include <osl/thread.h>
#include <rtl/ustring.hxx>
#include <rtl/strbuf.hxx>
#include <unotools/tempfile.hxx>
#include <algorithm>
using namespace vcl;
using namespace psp;
GlyphSet::GlyphSet (sal_Int32 nFontID, bool bVertical)
: mnFontID (nFontID),
mbVertical (bVertical)
{
PrintFontManager &rMgr = PrintFontManager::get();
maBaseName = OUStringToOString (rMgr.getPSName(mnFontID),
RTL_TEXTENCODING_ASCII_US);
}
void
GlyphSet::GetGlyphID (
sal_GlyphId nGlyph,
unsigned char* nOutGlyphID,
sal_Int32* nOutGlyphSetID
)
{
if (!LookupGlyphID(nGlyph, nOutGlyphID, nOutGlyphSetID))
AddGlyphID(nGlyph, nOutGlyphID, nOutGlyphSetID);
}
bool
GlyphSet::LookupGlyphID (
sal_GlyphId nGlyph,
unsigned char* nOutGlyphID,
sal_Int32* nOutGlyphSetID
)
{
sal_Int32 nGlyphSetID = 1;
// loop through all the font subsets
for (auto const& glyph : maGlyphList)
{
// check every subset if it contains the queried unicode char
glyph_map_t::const_iterator aGlyph = glyph.find (nGlyph);
if (aGlyph != glyph.end())
{
// success: found the glyph id, return the mapped glyphid and the glyphsetid
*nOutGlyphSetID = nGlyphSetID;
*nOutGlyphID = aGlyph->second;
return true;
}
++nGlyphSetID;
}
*nOutGlyphSetID = -1;
*nOutGlyphID = 0;
return false;
}
void
GlyphSet::AddNotdef (glyph_map_t &rGlyphMap)
{
if (rGlyphMap.empty())
rGlyphMap[0] = 0;
}
void
GlyphSet::AddGlyphID (
sal_GlyphId nGlyph,
unsigned char* nOutGlyphID,
sal_Int32* nOutGlyphSetID
)
{
// create an empty glyphmap that is reserved for unencoded symbol glyphs,
// and a second map that takes any other
if (maGlyphList.empty())
{
glyph_map_t aMap, aMapp;
maGlyphList.push_back (aMap);
maGlyphList.push_back (aMapp);
}
// if the last map is full, create a new one
if (maGlyphList.back().size() == 255)
{
glyph_map_t aMap;
maGlyphList.push_back (aMap);
}
glyph_map_t& aGlyphSet = maGlyphList.back();
AddNotdef (aGlyphSet);
int nSize = aGlyphSet.size();
aGlyphSet [nGlyph] = nSize;
*nOutGlyphSetID = maGlyphList.size();
*nOutGlyphID = aGlyphSet [nGlyph];
}
OString
GlyphSet::GetGlyphSetName (sal_Int32 nGlyphSetID)
{
OStringBuffer aSetName( maBaseName.getLength() + 32 );
aSetName.append( maBaseName
+ "FID" +
OString::number( mnFontID ) );
aSetName.append( mbVertical ? "VGSet" : "HGSet" );
aSetName.append( nGlyphSetID );
return aSetName.makeStringAndClear();
}
OString
GlyphSet::GetReencodedFontName (rtl_TextEncoding nEnc, std::string_view rFontName)
{
if ( nEnc == RTL_TEXTENCODING_MS_1252
|| nEnc == RTL_TEXTENCODING_ISO_8859_1)
{
return OString::Concat(rFontName) + "-iso1252";
}
else
if (nEnc >= RTL_TEXTENCODING_USER_START && nEnc <= RTL_TEXTENCODING_USER_END)
{
return OString::Concat(rFontName)
+ "-enc"
+ OString::number(nEnc - RTL_TEXTENCODING_USER_START);
}
else
{
return OString();
}
}
void GlyphSet::DrawGlyph(PrinterGfx& rGfx,
const Point& rPoint,
const sal_GlyphId nGlyphId)
{
unsigned char nGlyphID;
sal_Int32 nGlyphSetID;
// convert to font glyph id and font subset
GetGlyphID (nGlyphId, &nGlyphID, &nGlyphSetID);
OString aGlyphSetName = GetGlyphSetName(nGlyphSetID);
rGfx.PSSetFont (aGlyphSetName, RTL_TEXTENCODING_DONTKNOW);
rGfx.PSMoveTo (rPoint);
rGfx.PSShowGlyph(nGlyphID);
}
namespace {
struct EncEntry
{
unsigned char aEnc;
tools::Long aGID;
EncEntry() : aEnc( 0 ), aGID( 0 ) {}
bool operator<( const EncEntry& rRight ) const
{ return aEnc < rRight.aEnc; }
};
}
static void CreatePSUploadableFont( TrueTypeFont* pSrcFont, SvStream* pTmpFile,
const char* pGlyphSetName, int nGlyphCount,
/*const*/ const sal_uInt16* pRequestedGlyphs, /*const*/ const unsigned char* pEncoding,
bool bAllowType42 )
{
// match the font-subset to the printer capabilities
// TODO: allow CFF for capable printers
FontType nTargetMask = FontType::TYPE1_PFA | FontType::TYPE3_FONT;
if( bAllowType42 )
nTargetMask |= FontType::TYPE42_FONT;
std::vector< EncEntry > aSorted( nGlyphCount, EncEntry() );
for( int i = 0; i < nGlyphCount; i++ )
{
aSorted[i].aEnc = pEncoding[i];
aSorted[i].aGID = pRequestedGlyphs[i];
}
std::stable_sort( aSorted.begin(), aSorted.end() );
std::vector< unsigned char > aEncoding( nGlyphCount );
std::vector< sal_GlyphId > aRequestedGlyphs( nGlyphCount );
for( int i = 0; i < nGlyphCount; i++ )
{
aEncoding[i] = aSorted[i].aEnc;
aRequestedGlyphs[i] = aSorted[i].aGID;
}
FontSubsetInfo aInfo;
aInfo.LoadFont( pSrcFont );
aInfo.CreateFontSubset( nTargetMask, pTmpFile, pGlyphSetName,
aRequestedGlyphs.data(), aEncoding.data(), nGlyphCount );
}
void
GlyphSet::PSUploadFont (osl::File& rOutFile, PrinterGfx &rGfx, bool bAllowType42, std::vector< OString >& rSuppliedFonts )
{
TrueTypeFont *pTTFont;
OString aTTFileName (rGfx.GetFontMgr().getFontFileSysPath(mnFontID));
int nFace = rGfx.GetFontMgr().getFontFaceNumber(mnFontID);
SFErrCodes nSuccess = OpenTTFontFile(aTTFileName.getStr(), nFace, &pTTFont);
if (nSuccess != SFErrCodes::Ok)
return;
utl::TempFileFast aTmpFile;
SvStream* pTmpFile = aTmpFile.GetStream(StreamMode::READWRITE);
// encoding vector maps character encoding to the ordinal number
// of the glyph in the output file
unsigned char pEncoding[256];
sal_uInt16 pTTGlyphMapping[256];
// loop through all the font glyph subsets
sal_Int32 nGlyphSetID = 1;
for (auto const& glyph : maGlyphList)
{
if (glyph.empty())
{
++nGlyphSetID;
continue;
}
// loop through all the glyphs in the subset
sal_Int32 n = 0;
for (auto const& elem : glyph)
{
pTTGlyphMapping [n] = elem.first;
pEncoding [n] = elem.second;
n++;
}
// create the current subset
OString aGlyphSetName = GetGlyphSetName(nGlyphSetID);
pTmpFile->WriteOString( Concat2View(OString::Concat("%%BeginResource: font ")+ aGlyphSetName + "\n") );
CreatePSUploadableFont( pTTFont, pTmpFile, aGlyphSetName.getStr(), glyph.size(),
pTTGlyphMapping, pEncoding, bAllowType42 );
pTmpFile->WriteOString("%%EndResource\n" );
rSuppliedFonts.push_back( aGlyphSetName );
++nGlyphSetID;
}
// copy the file into the page header
pTmpFile->Seek(0);
pTmpFile->Flush();
unsigned char pBuffer[0x2000];
sal_uInt64 nIn;
sal_uInt64 nOut;
do
{
nIn = pTmpFile->ReadBytes(pBuffer, sizeof(pBuffer));
rOutFile.write (pBuffer, nIn, nOut);
}
while ((nIn == nOut) && !pTmpFile->eof());
// cleanup
CloseTTFont (pTTFont);
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/print/glyphset.hxx b/vcl/unx/generic/print/glyphset.hxx
deleted file mode 100644
index db7fe72..0000000
--- a/vcl/unx/generic/print/glyphset.hxx
+++ /dev/null
@@ -1,81 +0,0 @@
/* -*- 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 .
*/
#pragma once
#include <osl/file.hxx>
#include <rtl/string.hxx>
#include <glyphid.hxx>
#include <string_view>
#include <vector>
#include <unordered_map>
class Point;
namespace psp {
class PrinterGfx;
class PrintFontManager;
class GlyphSet
{
private:
sal_Int32 mnFontID;
bool mbVertical;
OString maBaseName;
typedef std::unordered_map< sal_GlyphId, sal_uInt8 > glyph_map_t;
std::vector< glyph_map_t > maGlyphList;
OString GetGlyphSetName (sal_Int32 nGlyphSetID);
void GetGlyphID (sal_GlyphId nGlyphId,
unsigned char* nOutGlyphID, sal_Int32* nOutGlyphSetID);
bool LookupGlyphID (sal_GlyphId nGlyphId,
unsigned char* nOutGlyphID, sal_Int32* nOutGlyphSetID);
void AddGlyphID (sal_GlyphId nGlyphId,
unsigned char* nOutGlyphID,
sal_Int32* nOutGlyphSetID);
static void AddNotdef (glyph_map_t &rGlyphMap);
public:
GlyphSet (sal_Int32 nFontID, bool bVertical);
/* FIXME delete the glyphlist in ~GlyphSet ??? */
sal_Int32 GetFontID () const { return mnFontID;}
static OString
GetReencodedFontName (rtl_TextEncoding nEnc,
std::string_view rFontName);
bool IsVertical () const { return mbVertical;}
void DrawGlyph (PrinterGfx& rGfx,
const Point& rPoint,
const sal_GlyphId nGlyphId);
void PSUploadFont (osl::File& rOutFile, PrinterGfx &rGfx, bool bAsType42, std::vector< OString >& rSuppliedFonts );
};
} /* namespace psp */
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/print/printerjob.cxx b/vcl/unx/generic/print/printerjob.cxx
deleted file mode 100644
index 5bfe6b7..0000000
--- a/vcl/unx/generic/print/printerjob.cxx
+++ /dev/null
@@ -1,969 +0,0 @@
/* -*- 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 <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include "psputil.hxx"
#include <unx/printerjob.hxx>
#include <unx/printergfx.hxx>
#include <ppdparser.hxx>
#include <strhelper.hxx>
#include <printerinfomanager.hxx>
#include <rtl/ustring.hxx>
#include <rtl/strbuf.hxx>
#include <rtl/ustrbuf.hxx>
#include <osl/thread.h>
#include <osl/security.hxx>
#include <algorithm>
#include <cstddef>
#include <deque>
#include <vector>
using namespace psp;
#define nBLOCKSIZE 0x2000
namespace psp
{
static bool
AppendPS (FILE* pDst, osl::File* pSrc, unsigned char* pBuffer)
{
assert(pBuffer);
if ((pDst == nullptr) || (pSrc == nullptr))
return false;
if (pSrc->setPos(osl_Pos_Absolut, 0) != osl::FileBase::E_None)
return false;
sal_uInt64 nIn = 0;
sal_uInt64 nOut = 0;
do
{
pSrc->read (pBuffer, nBLOCKSIZE, nIn);
if (nIn > 0)
nOut = fwrite (pBuffer, 1, sal::static_int_cast<sal_uInt32>(nIn), pDst);
}
while ((nIn > 0) && (nIn == nOut));
return true;
}
} // namespace psp
/*
* private convenience routines for file handling
*/
std::unique_ptr<osl::File>
PrinterJob::CreateSpoolFile (std::u16string_view rName, std::u16string_view rExtension) const
{
OUString aFile = OUString::Concat(rName) + rExtension;
OUString aFileURL;
osl::File::RC nError = osl::File::getFileURLFromSystemPath( aFile, aFileURL );
if (nError != osl::File::E_None)
return nullptr;
aFileURL = maSpoolDirName + "/" + aFileURL;
std::unique_ptr<osl::File> pFile( new osl::File (aFileURL) );
nError = pFile->open (osl_File_OpenFlag_Read | osl_File_OpenFlag_Write | osl_File_OpenFlag_Create);
if (nError != osl::File::E_None)
{
return nullptr;
}
osl::File::setAttributes (aFileURL,
osl_File_Attribute_OwnWrite | osl_File_Attribute_OwnRead);
return pFile;
}
/*
* public methods of PrinterJob: for use in PrinterGfx
*/
void
PrinterJob::GetScale (double &rXScale, double &rYScale) const
{
rXScale = mfXScale;
rYScale = mfYScale;
}
sal_uInt16
PrinterJob::GetDepth () const
{
sal_Int32 nLevel = GetPostscriptLevel();
bool bColor = IsColorPrinter ();
return nLevel > 1 && bColor ? 24 : 8;
}
sal_uInt16
PrinterJob::GetPostscriptLevel (const JobData *pJobData) const
{
sal_uInt16 nPSLevel = 2;
if( pJobData == nullptr )
pJobData = &m_aLastJobData;
if( pJobData->m_nPSLevel )
nPSLevel = pJobData->m_nPSLevel;
else
if( pJobData->m_pParser )
nPSLevel = pJobData->m_pParser->getLanguageLevel();
return nPSLevel;
}
bool
PrinterJob::IsColorPrinter () const
{
bool bColor = false;
if( m_aLastJobData.m_nColorDevice )
bColor = m_aLastJobData.m_nColorDevice != -1;
else if( m_aLastJobData.m_pParser )
bColor = m_aLastJobData.m_pParser->isColorDevice();
return bColor;
}
osl::File*
PrinterJob::GetCurrentPageBody ()
{
return maPageVector.back().get();
}
/*
* public methods of PrinterJob: the actual job / spool handling
*/
PrinterJob::PrinterJob()
: mnFileMode(0)
, m_pGraphics(nullptr)
, mnResolution(96)
, mnWidthPt(0)
, mnHeightPt(0)
, mnMaxWidthPt(0)
, mnMaxHeightPt(0)
, mnLandscapes(0)
, mnPortraits(0)
, mnLMarginPt(0)
, mnRMarginPt(0)
, mnTMarginPt(0)
, mnBMarginPt(0)
, mfXScale(1)
, mfYScale(1)
, m_bQuickJob(false)
{
}
/* remove all our temporary files, uses external program "rm", since
osl functionality is inadequate */
static void
removeSpoolDir (const OUString& rSpoolDir)
{
OUString aSysPath;
if( osl::File::E_None != osl::File::getSystemPathFromFileURL( rSpoolDir, aSysPath ) )
{
// Conversion did not work, as this is quite a dangerous action,
// we should abort here...
OSL_FAIL( "psprint: couldn't remove spool directory" );
return;
}
OString aSysPathByte =
OUStringToOString (aSysPath, osl_getThreadTextEncoding());
if (system (OString("rm -rf " + aSysPathByte).getStr()) == -1)
OSL_FAIL( "psprint: couldn't remove spool directory" );
}
/* creates a spool directory with a "pidgin random" value based on
current system time */
static OUString
createSpoolDir ()
{
TimeValue aCur;
osl_getSystemTime( &aCur );
sal_Int32 nRand = aCur.Seconds ^ (aCur.Nanosec/1000);
OUString aTmpDir;
osl_getTempDirURL( &aTmpDir.pData );
do
{
OUString aDir = aTmpDir + "/psp" + OUString::number(nRand);
if( osl::Directory::create( aDir ) == osl::FileBase::E_None )
{
osl::File::setAttributes( aDir,
osl_File_Attribute_OwnWrite
| osl_File_Attribute_OwnRead
| osl_File_Attribute_OwnExe );
return aDir;
}
nRand++;
} while( nRand );
return OUString();
}
PrinterJob::~PrinterJob ()
{
maPageVector.clear();
maHeaderVector.clear();
// mpJobHeader->remove();
mpJobHeader.reset();
// mpJobTrailer->remove();
mpJobTrailer.reset();
// XXX should really call osl::remove routines
if( !maSpoolDirName.isEmpty() )
removeSpoolDir (maSpoolDirName);
// osl::Directory::remove (maSpoolDirName);
}
static void WriteLocalTimePS( osl::File *rFile )
{
TimeValue aStartTime, tLocal;
oslDateTime date_time;
if (osl_getSystemTime( &aStartTime ) &&
osl_getLocalTimeFromSystemTime( &aStartTime, &tLocal ) &&
osl_getDateTimeFromTimeValue( &tLocal, &date_time ))
{
char ar[ 256 ];
snprintf(
ar, sizeof (ar),
"%04d-%02d-%02d %02d:%02d:%02d ",
date_time.Year, date_time.Month, date_time.Day,
date_time.Hours, date_time.Minutes, date_time.Seconds );
WritePS( rFile, ar );
}
else
WritePS( rFile, "Unknown-Time" );
}
static bool isAscii( std::u16string_view rStr )
{
size_t nLen = rStr.size();
for( size_t i = 0; i < nLen; i++ )
if( rStr[i] > 127 )
return false;
return true;
}
bool
PrinterJob::StartJob (
const OUString& rFileName,
int nMode,
const OUString& rJobName,
std::u16string_view rAppName,
const JobData& rSetupData,
PrinterGfx* pGraphics,
bool bIsQuickJob
)
{
m_bQuickJob = bIsQuickJob;
mnMaxWidthPt = mnMaxHeightPt = 0;
mnLandscapes = mnPortraits = 0;
m_pGraphics = pGraphics;
InitPaperSize (rSetupData);
// create file container for document header and trailer
maFileName = rFileName;
mnFileMode = nMode;
maSpoolDirName = createSpoolDir ();
maJobTitle = rJobName;
OUString aExt(".ps");
mpJobHeader = CreateSpoolFile (u"psp_head", aExt);
mpJobTrailer = CreateSpoolFile (u"psp_tail", aExt);
if( ! (mpJobHeader && mpJobTrailer) ) // existing files are removed in destructor
return false;
// write document header according to Document Structuring Conventions (DSC)
WritePS (mpJobHeader.get(),
"%!PS-Adobe-3.0\n"
"%%BoundingBox: (atend)\n" );
// Creator (this application)
OUString aFilterWS = WhitespaceToSpace( rAppName, false );
WritePS (mpJobHeader.get(), "%%Creator: (");
WritePS (mpJobHeader.get(), aFilterWS);
WritePS (mpJobHeader.get(), ")\n");
// For (user name)
osl::Security aSecurity;
OUString aUserName;
if( aSecurity.getUserName( aUserName ) )
{
WritePS (mpJobHeader.get(), "%%For: (");
WritePS (mpJobHeader.get(), aUserName);
WritePS (mpJobHeader.get(), ")\n");
}
// Creation Date (locale independent local time)
WritePS (mpJobHeader.get(), "%%CreationDate: (");
WriteLocalTimePS (mpJobHeader.get());
WritePS (mpJobHeader.get(), ")\n");
// Document Title
/* #i74335#
* The title should be clean ascii; rJobName however may
* contain any Unicode character. So implement the following
* algorithm:
* use rJobName, if it contains only ascii
* use the filename, if it contains only ascii
* else omit %%Title
*/
aFilterWS = WhitespaceToSpace( rJobName, false );
OUString aTitle( aFilterWS );
if( ! isAscii( aTitle ) )
{
aTitle = WhitespaceToSpace( rFileName.subView(rFileName.lastIndexOf('/')+1), false );
if( ! isAscii( aTitle ) )
aTitle.clear();
}
maJobTitle = aFilterWS;
if( !aTitle.isEmpty() )
{
WritePS (mpJobHeader.get(), "%%Title: (");
WritePS (mpJobHeader.get(), aTitle);
WritePS (mpJobHeader.get(), ")\n");
}
// Language Level
OStringBuffer pLevel;
getValueOf(GetPostscriptLevel(&rSetupData), pLevel);
pLevel.append('\n');
WritePS (mpJobHeader.get(), "%%LanguageLevel: ");
WritePS (mpJobHeader.get(), pLevel.makeStringAndClear());
// Other
WritePS (mpJobHeader.get(), "%%DocumentData: Clean7Bit\n");
WritePS (mpJobHeader.get(), "%%Pages: (atend)\n");
WritePS (mpJobHeader.get(), "%%Orientation: (atend)\n");
WritePS (mpJobHeader.get(), "%%PageOrder: Ascend\n");
WritePS (mpJobHeader.get(), "%%EndComments\n");
// write Prolog
writeProlog (mpJobHeader.get(), rSetupData);
// mark last job setup as not set
m_aLastJobData.m_pParser = nullptr;
m_aLastJobData.m_aContext.setParser( nullptr );
return true;
}
bool
PrinterJob::EndJob()
{
// no pages ? that really means no print job
if( maPageVector.empty() )
return false;
// write document setup (done here because it
// includes the accumulated fonts
if( mpJobHeader )
writeSetup( mpJobHeader.get(), m_aDocumentJobData );
m_pGraphics->OnEndJob();
if( ! (mpJobHeader && mpJobTrailer) )
return false;
// write document trailer according to Document Structuring Conventions (DSC)
OStringBuffer aTrailer(512);
aTrailer.append( "%%Trailer\n"
"%%BoundingBox: 0 0 "
+ OString::number( static_cast<sal_Int32>(mnMaxWidthPt) )
+ " "
+ OString::number( static_cast<sal_Int32>(mnMaxHeightPt) ) );
if( mnLandscapes > mnPortraits )
aTrailer.append("\n%%Orientation: Landscape");
else
aTrailer.append("\n%%Orientation: Portrait");
aTrailer.append( "\n%%Pages: "
+ OString::number( static_cast<sal_Int32>(maPageVector.size()) )
+ "\n%%EOF\n" );
WritePS (mpJobTrailer.get(), aTrailer.getStr());
/*
* spool the set of files to their final destination, this is U**X dependent
*/
FILE* pDestFILE = nullptr;
/* create a destination either as file or as a pipe */
bool bSpoolToFile = !maFileName.isEmpty();
if (bSpoolToFile)
{
const OString aFileName = OUStringToOString (maFileName,
osl_getThreadTextEncoding());
if( mnFileMode )
{
int nFile = open( aFileName.getStr(), O_CREAT | O_EXCL | O_RDWR, mnFileMode );
if( nFile != -1 )
{
pDestFILE = fdopen( nFile, "w" );
if( pDestFILE == nullptr )
{
close( nFile );
unlink( aFileName.getStr() );
return false;
}
}
else
{
(void)chmod( aFileName.getStr(), mnFileMode );
}
}
if (pDestFILE == nullptr)
pDestFILE = fopen (aFileName.getStr(), "w");
if (pDestFILE == nullptr)
return false;
}
else
{
PrinterInfoManager& rPrinterInfoManager = PrinterInfoManager::get ();
pDestFILE = rPrinterInfoManager.startSpool( m_aLastJobData.m_aPrinterName, m_bQuickJob );
if (pDestFILE == nullptr)
return false;
}
/* spool the document parts to the destination */
unsigned char pBuffer[ nBLOCKSIZE ];
AppendPS (pDestFILE, mpJobHeader.get(), pBuffer);
mpJobHeader->close();
bool bSuccess = true;
std::vector< std::unique_ptr<osl::File> >::iterator pPageBody;
std::vector< std::unique_ptr<osl::File> >::iterator pPageHead;
for (pPageBody = maPageVector.begin(), pPageHead = maHeaderVector.begin();
pPageBody != maPageVector.end() && pPageHead != maHeaderVector.end();
++pPageBody, ++pPageHead)
{
if( *pPageHead )
{
osl::File::RC nError = (*pPageHead)->open(osl_File_OpenFlag_Read);
if (nError == osl::File::E_None)
{
AppendPS (pDestFILE, pPageHead->get(), pBuffer);
(*pPageHead)->close();
}
}
else
bSuccess = false;
if( *pPageBody )
{
osl::File::RC nError = (*pPageBody)->open(osl_File_OpenFlag_Read);
if (nError == osl::File::E_None)
{
AppendPS (pDestFILE, pPageBody->get(), pBuffer);
(*pPageBody)->close();
}
}
else
bSuccess = false;
}
AppendPS (pDestFILE, mpJobTrailer.get(), pBuffer);
mpJobTrailer->close();
/* well done */
if (bSpoolToFile)
fclose (pDestFILE);
else
{
PrinterInfoManager& rPrinterInfoManager = PrinterInfoManager::get();
if (!rPrinterInfoManager.endSpool( m_aLastJobData.m_aPrinterName,
maJobTitle, pDestFILE, m_aDocumentJobData, true, OUString()))
{
bSuccess = false;
}
}
return bSuccess;
}
void
PrinterJob::InitPaperSize (const JobData& rJobSetup)
{
int nRes = rJobSetup.m_aContext.getRenderResolution ();
OUString aPaper;
int nWidth, nHeight;
rJobSetup.m_aContext.getPageSize (aPaper, nWidth, nHeight);
int nLeft = 0, nRight = 0, nUpper = 0, nLower = 0;
const PPDParser* pParser = rJobSetup.m_aContext.getParser();
if (pParser != nullptr)
pParser->getMargins (aPaper, nLeft, nRight, nUpper, nLower);
mnResolution = nRes;
mnWidthPt = nWidth;
mnHeightPt = nHeight;
if( mnWidthPt > mnMaxWidthPt )
mnMaxWidthPt = mnWidthPt;
if( mnHeightPt > mnMaxHeightPt )
mnMaxHeightPt = mnHeightPt;
mnLMarginPt = nLeft;
mnRMarginPt = nRight;
mnTMarginPt = nUpper;
mnBMarginPt = nLower;
mfXScale = 72.0 / static_cast<double>(mnResolution);
mfYScale = -1.0 * 72.0 / static_cast<double>(mnResolution);
}
void
PrinterJob::StartPage (const JobData& rJobSetup)
{
InitPaperSize (rJobSetup);
OUString aPageNo = OUString::number (static_cast<sal_Int32>(maPageVector.size())+1); // sequential page number must start with 1
OUString aExt = aPageNo + ".ps";
maHeaderVector.push_back( CreateSpoolFile ( u"psp_pghead", aExt) );
maPageVector.push_back( CreateSpoolFile ( u"psp_pgbody", aExt) );
osl::File* pPageHeader = maHeaderVector.back().get();
osl::File* pPageBody = maPageVector.back().get();
if( ! (pPageHeader && pPageBody) )
return;
// write page header according to Document Structuring Conventions (DSC)
WritePS (pPageHeader, "%%Page: ");
WritePS (pPageHeader, aPageNo);
WritePS (pPageHeader, " ");
WritePS (pPageHeader, aPageNo);
WritePS (pPageHeader, "\n");
if( rJobSetup.m_eOrientation == orientation::Landscape )
{
WritePS (pPageHeader, "%%PageOrientation: Landscape\n");
mnLandscapes++;
}
else
{
WritePS (pPageHeader, "%%PageOrientation: Portrait\n");
mnPortraits++;
}
OStringBuffer pBBox;
psp::appendStr ("%%PageBoundingBox: ", pBBox);
psp::getValueOf (mnLMarginPt, pBBox);
psp::appendStr (" ", pBBox);
psp::getValueOf (mnBMarginPt, pBBox);
psp::appendStr (" ", pBBox);
psp::getValueOf (mnWidthPt - mnRMarginPt, pBBox);
psp::appendStr (" ", pBBox);
psp::getValueOf (mnHeightPt - mnTMarginPt, pBBox);
psp::appendStr ("\n", pBBox);
WritePS (pPageHeader, pBBox.makeStringAndClear());
/* #i7262# #i65491# write setup only before first page
* (to %%Begin(End)Setup, instead of %%Begin(End)PageSetup)
* don't do this in StartJob since the jobsetup there may be
* different.
*/
bool bWriteFeatures = true;
if( 1 == maPageVector.size() )
{
m_aDocumentJobData = rJobSetup;
bWriteFeatures = false;
}
if ( writePageSetup( pPageHeader, rJobSetup, bWriteFeatures ) )
{
m_aLastJobData = rJobSetup;
}
}
void
PrinterJob::EndPage ()
{
osl::File* pPageHeader = maHeaderVector.back().get();
osl::File* pPageBody = maPageVector.back().get();
if( ! (pPageBody && pPageHeader) )
return;
// copy page to paper and write page trailer according to DSC
OStringBuffer pTrailer;
psp::appendStr ("grestore grestore\n", pTrailer);
psp::appendStr ("showpage\n", pTrailer);
psp::appendStr ("%%PageTrailer\n\n", pTrailer);
WritePS (pPageBody, pTrailer.makeStringAndClear());
// this page is done for now, close it to avoid having too many open fd's
pPageHeader->close();
pPageBody->close();
}
namespace {
struct less_ppd_key
{
bool operator()(const PPDKey* left, const PPDKey* right)
{ return left->getOrderDependency() < right->getOrderDependency(); }
};
}
static bool writeFeature( osl::File* pFile, const PPDKey* pKey, const PPDValue* pValue, bool bUseIncluseFeature )
{
if( ! pKey || ! pValue )
return true;
OStringBuffer aFeature(256);
aFeature.append( "[{\n" );
if( bUseIncluseFeature )
aFeature.append( "%%IncludeFeature:" );
else
aFeature.append( "%%BeginFeature:" );
aFeature.append( " *"
+ OUStringToOString( pKey->getKey(), RTL_TEXTENCODING_ASCII_US )
+ " "
+ OUStringToOString( pValue->m_aOption, RTL_TEXTENCODING_ASCII_US ) );
if( !bUseIncluseFeature )
{
aFeature.append( "\n"
+ OUStringToOString( pValue->m_aValue, RTL_TEXTENCODING_ASCII_US )
+ "\n%%EndFeature" );
}
aFeature.append( "\n} stopped cleartomark\n" );
sal_uInt64 nWritten = 0;
return !(pFile->write( aFeature.getStr(), aFeature.getLength(), nWritten )
|| nWritten != static_cast<sal_uInt64>(aFeature.getLength()));
}
bool PrinterJob::writeFeatureList( osl::File* pFile, const JobData& rJob, bool bDocumentSetup ) const
{
bool bSuccess = true;
// emit features ordered to OrderDependency
// ignore features that are set to default
// sanity check
if( rJob.m_pParser == rJob.m_aContext.getParser() &&
rJob.m_pParser &&
( m_aLastJobData.m_pParser == rJob.m_pParser || m_aLastJobData.m_pParser == nullptr )
)
{
std::size_t i;
std::size_t nKeys = rJob.m_aContext.countValuesModified();
::std::vector< const PPDKey* > aKeys( nKeys );
for( i = 0; i < nKeys; i++ )
aKeys[i] = rJob.m_aContext.getModifiedKey( i );
::std::sort( aKeys.begin(), aKeys.end(), less_ppd_key() );
for( i = 0; i < nKeys && bSuccess; i++ )
{
const PPDKey* pKey = aKeys[i];
bool bEmit = false;
if( bDocumentSetup )
{
if( pKey->getSetupType() == PPDKey::SetupType::DocumentSetup )
bEmit = true;
}
if( pKey->getSetupType() == PPDKey::SetupType::PageSetup ||
pKey->getSetupType() == PPDKey::SetupType::AnySetup )
bEmit = true;
if( bEmit )
{
const PPDValue* pValue = rJob.m_aContext.getValue( pKey );
if( pValue
&& pValue->m_eType == eInvocation
&& ( m_aLastJobData.m_pParser == nullptr
|| m_aLastJobData.m_aContext.getValue( pKey ) != pValue
|| bDocumentSetup
)
)
{
// try to avoid PS level 2 feature commands if level is set to 1
if( GetPostscriptLevel( &rJob ) == 1 )
{
bool bHavePS2 =
( pValue->m_aValue.indexOf( "<<" ) != -1 )
||
( pValue->m_aValue.indexOf( ">>" ) != -1 );
if( bHavePS2 )
continue;
}
bSuccess = writeFeature( pFile, pKey, pValue, PrinterInfoManager::get().getUseIncludeFeature() );
}
}
}
}
else
bSuccess = false;
return bSuccess;
}
bool PrinterJob::writePageSetup( osl::File* pFile, const JobData& rJob, bool bWriteFeatures )
{
bool bSuccess = true;
WritePS (pFile, "%%BeginPageSetup\n%\n");
if ( bWriteFeatures )
bSuccess = writeFeatureList( pFile, rJob, false );
WritePS (pFile, "%%EndPageSetup\n");
OStringBuffer pTranslate;
if( rJob.m_eOrientation == orientation::Portrait )
{
psp::appendStr ("gsave\n[", pTranslate);
psp::getValueOfDouble ( pTranslate, mfXScale, 5);
psp::appendStr (" 0 0 ", pTranslate);
psp::getValueOfDouble ( pTranslate, mfYScale, 5);
psp::appendStr (" ", pTranslate);
psp::getValueOf (mnRMarginPt, pTranslate);
psp::appendStr (" ", pTranslate);
psp::getValueOf (mnHeightPt-mnTMarginPt,
pTranslate);
psp::appendStr ("] concat\ngsave\n",
pTranslate);
}
else
{
psp::appendStr ("gsave\n", pTranslate);
psp::appendStr ("[ 0 ", pTranslate);
psp::getValueOfDouble ( pTranslate, -mfYScale, 5);
psp::appendStr (" ", pTranslate);
psp::getValueOfDouble ( pTranslate, mfXScale, 5);
psp::appendStr (" 0 ", pTranslate );
psp::getValueOfDouble ( pTranslate, mnLMarginPt, 5 );
psp::appendStr (" ", pTranslate);
psp::getValueOf (mnBMarginPt, pTranslate );
psp::appendStr ("] concat\ngsave\n",
pTranslate);
}
WritePS (pFile, pTranslate.makeStringAndClear());
return bSuccess;
}
void PrinterJob::writeJobPatch( osl::File* pFile, const JobData& rJobData )
{
if( ! PrinterInfoManager::get().getUseJobPatch() )
return;
const PPDKey* pKey = nullptr;
if( rJobData.m_pParser )
pKey = rJobData.m_pParser->getKey( "JobPatchFile" );
if( ! pKey )
return;
// order the patch files
// according to PPD spec the JobPatchFile options must be int
// and should be emitted in order
std::deque< sal_Int32 > patch_order;
int nValueCount = pKey->countValues();
for( int i = 0; i < nValueCount; i++ )
{
const PPDValue* pVal = pKey->getValue( i );
patch_order.push_back( pVal->m_aOption.toInt32() );
if( patch_order.back() == 0 && pVal->m_aOption != "0" )
{
WritePS( pFile, "% Warning: left out JobPatchFile option \"" );
OString aOption = OUStringToOString( pVal->m_aOption, RTL_TEXTENCODING_ASCII_US );
WritePS( pFile, aOption.getStr() );
WritePS( pFile,
"\"\n% as it violates the PPD spec;\n"
"% JobPatchFile options need to be numbered for ordering.\n" );
}
}
std::sort(patch_order.begin(), patch_order.end());
patch_order.erase(std::unique(patch_order.begin(), patch_order.end()), patch_order.end());
for (auto const& elem : patch_order)
{
// note: this discards patch files not adhering to the "int" scheme
// as there won't be a value for them
writeFeature( pFile, pKey, pKey->getValue( OUString::number(elem) ), false );
}
}
void PrinterJob::writeProlog (osl::File* pFile, const JobData& rJobData )
{
WritePS( pFile, "%%BeginProlog\n" );
// JobPatchFile feature needs to be emitted at begin of prolog
writeJobPatch( pFile, rJobData );
static const char pProlog[] = {
"%%BeginResource: procset PSPrint-Prolog 1.0 0\n"
"/ISO1252Encoding [\n"
"/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
"/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
"/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
"/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
"/space /exclam /quotedbl /numbersign /dollar /percent /ampersand /quotesingle\n"
"/parenleft /parenright /asterisk /plus /comma /hyphen /period /slash\n"
"/zero /one /two /three /four /five /six /seven\n"
"/eight /nine /colon /semicolon /less /equal /greater /question\n"
"/at /A /B /C /D /E /F /G\n"
"/H /I /J /K /L /M /N /O\n"
"/P /Q /R /S /T /U /V /W\n"
"/X /Y /Z /bracketleft /backslash /bracketright /asciicircum /underscore\n"
"/grave /a /b /c /d /e /f /g\n"
"/h /i /j /k /l /m /n /o\n"
"/p /q /r /s /t /u /v /w\n"
"/x /y /z /braceleft /bar /braceright /asciitilde /unused\n"
"/Euro /unused /quotesinglbase /florin /quotedblbase /ellipsis /dagger /daggerdbl\n"
"/circumflex /perthousand /Scaron /guilsinglleft /OE /unused /Zcaron /unused\n"
"/unused /quoteleft /quoteright /quotedblleft /quotedblright /bullet /endash /emdash\n"
"/tilde /trademark /scaron /guilsinglright /oe /unused /zcaron /Ydieresis\n"
"/space /exclamdown /cent /sterling /currency /yen /brokenbar /section\n"
"/dieresis /copyright /ordfeminine /guillemotleft /logicalnot /hyphen /registered /macron\n"
"/degree /plusminus /twosuperior /threesuperior /acute /mu /paragraph /periodcentered\n"
"/cedilla /onesuperior /ordmasculine /guillemotright /onequarter /onehalf /threequarters /questiondown\n"
"/Agrave /Aacute /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla\n"
"/Egrave /Eacute /Ecircumflex /Edieresis /Igrave /Iacute /Icircumflex /Idieresis\n"
"/Eth /Ntilde /Ograve /Oacute /Ocircumflex /Otilde /Odieresis /multiply\n"
"/Oslash /Ugrave /Uacute /Ucircumflex /Udieresis /Yacute /Thorn /germandbls\n"
"/agrave /aacute /acircumflex /atilde /adieresis /aring /ae /ccedilla\n"
"/egrave /eacute /ecircumflex /edieresis /igrave /iacute /icircumflex /idieresis\n"
"/eth /ntilde /ograve /oacute /ocircumflex /otilde /odieresis /divide\n"
"/oslash /ugrave /uacute /ucircumflex /udieresis /yacute /thorn /ydieresis] def\n"
"\n"
"/psp_definefont { exch dup findfont dup length dict begin { 1 index /FID ne\n"
"{ def } { pop pop } ifelse } forall /Encoding 3 -1 roll def\n"
"currentdict end exch pop definefont pop } def\n"
"\n"
"/pathdict dup 8 dict def load begin\n"
"/rcmd { { currentfile 1 string readstring pop 0 get dup 32 gt { exit }\n"
"{ pop } ifelse } loop dup 126 eq { pop exit } if 65 sub dup 16#3 and 1\n"
"add exch dup 16#C and -2 bitshift 16#3 and 1 add exch 16#10 and 16#10\n"
"eq 3 1 roll exch } def\n"
"/rhex { dup 1 sub exch currentfile exch string readhexstring pop dup 0\n"
"get dup 16#80 and 16#80 eq dup 3 1 roll { 16#7f and } if 2 index 0 3\n"
"-1 roll put 3 1 roll 0 0 1 5 -1 roll { 2 index exch get add 256 mul }\n"
"for 256 div exch pop exch { neg } if } def\n"
"/xcmd { rcmd exch rhex exch rhex exch 5 -1 roll add exch 4 -1 roll add\n"
"1 index 1 index 5 -1 roll { moveto } { lineto } ifelse } def end\n"
"/readpath { 0 0 pathdict begin { xcmd } loop end pop pop } def\n"
"\n"
"systemdict /languagelevel known not {\n"
"/xshow { exch dup length 0 1 3 -1 roll 1 sub { dup 3 index exch get\n"
"exch 2 index exch get 1 string dup 0 4 -1 roll put currentpoint 3 -1\n"
"roll show moveto 0 rmoveto } for pop pop } def\n"
"/rectangle { 4 -2 roll moveto 1 index 0 rlineto 0 exch rlineto neg 0\n"
"rlineto closepath } def\n"
"/rectfill { rectangle fill } def\n"
"/rectstroke { rectangle stroke } def } if\n"
"/bshow { currentlinewidth 3 1 roll currentpoint 3 index show moveto\n"
"setlinewidth false charpath stroke setlinewidth } def\n"
"/bxshow { currentlinewidth 4 1 roll setlinewidth exch dup length 1 sub\n"
"0 1 3 -1 roll { 1 string 2 index 2 index get 1 index exch 0 exch put dup\n"
"currentpoint 3 -1 roll show moveto currentpoint 3 -1 roll false charpath\n"
"stroke moveto 2 index exch get 0 rmoveto } for pop pop setlinewidth } def\n"
"\n"
"/psp_lzwfilter { currentfile /ASCII85Decode filter /LZWDecode filter } def\n"
"/psp_ascii85filter { currentfile /ASCII85Decode filter } def\n"
"/psp_lzwstring { psp_lzwfilter 1024 string readstring } def\n"
"/psp_ascii85string { psp_ascii85filter 1024 string readstring } def\n"
"/psp_imagedict {\n"
"/psp_bitspercomponent { 3 eq { 1 }{ 8 } ifelse } def\n"
"/psp_decodearray { [ [0 1 0 1 0 1] [0 255] [0 1] [0 255] ] exch get }\n"
"def 7 dict dup\n"
"/ImageType 1 put dup\n"
"/Width 7 -1 roll put dup\n"
"/Height 5 index put dup\n"
"/BitsPerComponent 4 index psp_bitspercomponent put dup\n"
"/Decode 5 -1 roll psp_decodearray put dup\n"
"/ImageMatrix [1 0 0 1 0 0] dup 5 8 -1 roll put put dup\n"
"/DataSource 4 -1 roll 1 eq { psp_lzwfilter } { psp_ascii85filter } ifelse put\n"
"} def\n"
"%%EndResource\n"
"%%EndProlog\n"
};
WritePS (pFile, pProlog);
}
bool PrinterJob::writeSetup( osl::File* pFile, const JobData& rJob )
{
WritePS (pFile, "%%BeginSetup\n%\n");
// download fonts
std::vector< OString > aFonts;
m_pGraphics->writeResources( pFile, aFonts );
if( !aFonts.empty() )
{
std::vector< OString >::const_iterator it = aFonts.begin();
OStringBuffer aLine( 256 );
aLine.append( "%%DocumentSuppliedResources: font " + (*it) + "\n" );
WritePS ( pFile, aLine.getStr() );
while( (++it) != aFonts.end() )
{
aLine.setLength(0);
aLine.append( "%%+ font " + (*it) + "\n" );
WritePS ( pFile, aLine.getStr() );
}
}
bool bSuccess = true;
// in case of external print dialog the number of copies is prepended
// to the job, let us not complicate things by emitting our own copy count
bool bExternalDialog = PrinterInfoManager::get().checkFeatureToken( GetPrinterName(), "external_dialog" );
if( ! bExternalDialog && rJob.m_nCopies > 1 )
{
// setup code
OString aLine = "/#copies " +
OString::number(static_cast<sal_Int32>(rJob.m_nCopies)) +
" def\n";
sal_uInt64 nWritten = 0;
bSuccess = !(pFile->write(aLine.getStr(), aLine.getLength(), nWritten)
|| nWritten != static_cast<sal_uInt64>(aLine.getLength()));
if( bSuccess && GetPostscriptLevel( &rJob ) >= 2 )
WritePS (pFile, "<< /NumCopies null /Policies << /NumCopies 1 >> >> setpagedevice\n" );
}
bool bFeatureSuccess = writeFeatureList( pFile, rJob, true );
WritePS (pFile, "%%EndSetup\n");
return bSuccess && bFeatureSuccess;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/print/psputil.cxx b/vcl/unx/generic/print/psputil.cxx
deleted file mode 100644
index b483713..0000000
--- a/vcl/unx/generic/print/psputil.cxx
+++ /dev/null
@@ -1,184 +0,0 @@
/* -*- 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 <string.h>
#include "psputil.hxx"
namespace psp {
/*
* string convenience routines
*/
sal_Int32
getHexValueOf (sal_Int32 nValue, OStringBuffer& pBuffer)
{
const static char pHex [0x10] = {
'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
pBuffer.append(pHex [(nValue & 0xF0) >> 4]);
pBuffer.append(pHex [(nValue & 0x0F) ]);
return 2;
}
sal_Int32
getAlignedHexValueOf (sal_Int32 nValue, OStringBuffer& pBuffer)
{
// get sign
bool bNegative = nValue < 0;
nValue = bNegative ? -nValue : nValue;
// get required buffer size, must be a multiple of two
sal_Int32 nPrecision;
if (nValue < 0x80)
nPrecision = 2;
else
if (nValue < 0x8000)
nPrecision = 4;
else
if (nValue < 0x800000)
nPrecision = 6;
else
nPrecision = 8;
// convert the int into its hex representation, write it into the buffer
sal_Int32 nRet = nPrecision;
auto const start = pBuffer.getLength();
while (nPrecision)
{
OStringBuffer scratch;
nPrecision -= getHexValueOf (nValue % 256, scratch );
pBuffer.insert(start, scratch);
nValue /= 256;
}
// set sign bit
if (bNegative)
{
switch (pBuffer[start])
{
case '0' : pBuffer[start] = '8'; break;
case '1' : pBuffer[start] = '9'; break;
case '2' : pBuffer[start] = 'A'; break;
case '3' : pBuffer[start] = 'B'; break;
case '4' : pBuffer[start] = 'C'; break;
case '5' : pBuffer[start] = 'D'; break;
case '6' : pBuffer[start] = 'E'; break;
case '7' : pBuffer[start] = 'F'; break;
default: OSL_FAIL("Already a signed value");
}
}
// report precision
return nRet;
}
sal_Int32
getValueOf (sal_Int32 nValue, OStringBuffer& pBuffer)
{
sal_Int32 nChar = 0;
if (nValue < 0)
{
pBuffer.append('-');
++nChar;
nValue *= -1;
}
else
if (nValue == 0)
{
pBuffer.append('0');
++nChar;
return nChar;
}
char pInvBuffer [32];
sal_Int32 nInvChar = 0;
while (nValue > 0)
{
pInvBuffer [nInvChar++] = '0' + nValue % 10;
nValue /= 10;
}
while (nInvChar > 0)
{
pBuffer.append(pInvBuffer [--nInvChar]);
++nChar;
}
return nChar;
}
sal_Int32
appendStr (const char* pSrc, OStringBuffer& pDst)
{
sal_Int32 nBytes = strlen (pSrc);
pDst.append(pSrc, nBytes);
return nBytes;
}
/*
* copy strings to file
*/
bool
WritePS (osl::File* pFile, const char* pString)
{
sal_uInt64 nInLength = rtl_str_getLength (pString);
sal_uInt64 nOutLength = 0;
if (nInLength > 0 && pFile)
pFile->write (pString, nInLength, nOutLength);
return nInLength == nOutLength;
}
bool
WritePS (osl::File* pFile, const char* pString, sal_uInt64 nInLength)
{
sal_uInt64 nOutLength = 0;
if (nInLength > 0 && pFile)
pFile->write (pString, nInLength, nOutLength);
return nInLength == nOutLength;
}
bool
WritePS (osl::File* pFile, const OString &rString)
{
sal_uInt64 nInLength = rString.getLength();
sal_uInt64 nOutLength = 0;
if (nInLength > 0 && pFile)
pFile->write (rString.getStr(), nInLength, nOutLength);
return nInLength == nOutLength;
}
bool
WritePS (osl::File* pFile, std::u16string_view rString)
{
return WritePS (pFile, OUStringToOString(rString, RTL_TEXTENCODING_ASCII_US));
}
} /* namespace psp */
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/print/psputil.hxx b/vcl/unx/generic/print/psputil.hxx
deleted file mode 100644
index e5ae180..0000000
--- a/vcl/unx/generic/print/psputil.hxx
+++ /dev/null
@@ -1,55 +0,0 @@
/* -*- 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 .
*/
#pragma once
#include <sal/config.h>
#include <string_view>
#include <osl/file.hxx>
#include <rtl/math.hxx>
#include <rtl/ustring.hxx>
#include <rtl/strbuf.hxx>
#include <rtl/string.hxx>
namespace psp {
/*
* string convenience routines
*/
sal_Int32 getHexValueOf (sal_Int32 nValue, OStringBuffer& pBuffer);
sal_Int32 getAlignedHexValueOf (sal_Int32 nValue, OStringBuffer& pBuffer);
sal_Int32 getValueOf (sal_Int32 nValue, OStringBuffer& pBuffer);
sal_Int32 appendStr (const char* pSrc, OStringBuffer& pDst);
inline void getValueOfDouble( OStringBuffer& pBuffer, double f, int nPrecision = 0)
{
pBuffer.append(rtl::math::doubleToString( f, rtl_math_StringFormat_G, nPrecision, '.', true ));
}
bool WritePS (osl::File* pFile, const char* pString);
bool WritePS (osl::File* pFile, const char* pString, sal_uInt64 nInLength);
bool WritePS (osl::File* pFile, const OString &rString);
bool WritePS (osl::File* pFile, std::u16string_view rString);
} /* namespace psp */
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/print/text_gfx.cxx b/vcl/unx/generic/print/text_gfx.cxx
deleted file mode 100644
index d847004..0000000
--- a/vcl/unx/generic/print/text_gfx.cxx
+++ /dev/null
@@ -1,158 +0,0 @@
/* -*- 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 "psputil.hxx"
#include "glyphset.hxx"
#include <unx/printergfx.hxx>
#include <unx/fontmanager.hxx>
using namespace psp ;
/*
* implement text handling printer routines,
*/
void PrinterGfx::SetFont(
sal_Int32 nFontID,
sal_Int32 nHeight,
sal_Int32 nWidth,
Degree10 nAngle,
bool bVertical,
bool bArtItalic,
bool bArtBold
)
{
// font and encoding will be set by drawText again immediately
// before PSShowText
mnFontID = nFontID;
maVirtualStatus.maFont.clear();
maVirtualStatus.maEncoding = RTL_TEXTENCODING_DONTKNOW;
maVirtualStatus.mnTextHeight = nHeight;
maVirtualStatus.mnTextWidth = nWidth;
maVirtualStatus.mbArtItalic = bArtItalic;
maVirtualStatus.mbArtBold = bArtBold;
mnTextAngle = nAngle;
mbTextVertical = bVertical;
}
void PrinterGfx::drawGlyph(const Point& rPoint,
sal_GlyphId aGlyphId)
{
// draw the string
// search for a glyph set matching the set font
bool bGlyphFound = false;
for (auto & elem : maPS3Font)
if ( (elem.GetFontID() == mnFontID)
&& (elem.IsVertical() == mbTextVertical))
{
elem.DrawGlyph (*this, rPoint, aGlyphId);
bGlyphFound = true;
break;
}
// not found ? create a new one
if (!bGlyphFound)
{
maPS3Font.emplace_back(mnFontID, mbTextVertical);
maPS3Font.back().DrawGlyph (*this, rPoint, aGlyphId);
}
}
void PrinterGfx::DrawGlyph(const Point& rPoint,
const GlyphItem& rGlyph)
{
// move and rotate the user coordinate system
// avoid the gsave/grestore for the simple cases since it allows
// reuse of the current font if it hasn't changed
Degree10 nCurrentTextAngle = mnTextAngle;
Point aPoint( rPoint );
if (nCurrentTextAngle)
{
PSGSave ();
PSTranslate (rPoint);
PSRotate (nCurrentTextAngle);
mnTextAngle = 0_deg10;
aPoint = Point( 0, 0 );
}
if (mbTextVertical && rGlyph.IsVertical())
{
sal_Int32 nTextHeight = maVirtualStatus.mnTextHeight;
sal_Int32 nTextWidth = maVirtualStatus.mnTextWidth ? maVirtualStatus.mnTextWidth : maVirtualStatus.mnTextHeight;
sal_Int32 nAscend = mrFontMgr.getFontAscend( mnFontID );
sal_Int32 nDescend = mrFontMgr.getFontDescend( mnFontID );
nDescend = nDescend * nTextHeight / 1000;
nAscend = nAscend * nTextHeight / 1000;
Point aRotPoint( -nDescend*nTextWidth/nTextHeight, nAscend*nTextWidth/nTextHeight );
// transform matrix to new individual direction
PSGSave ();
GraphicsStatus aSaveStatus = maVirtualStatus;
// switch font aspect
maVirtualStatus.mnTextWidth = nTextHeight;
maVirtualStatus.mnTextHeight = nTextWidth;
if( aPoint.X() || aPoint.Y() )
PSTranslate( aPoint );
PSRotate (900_deg10);
// draw the rotated glyph
drawGlyph(aRotPoint, rGlyph.glyphId());
// restore previous state
maVirtualStatus = aSaveStatus;
PSGRestore();
}
else
drawGlyph(aPoint, rGlyph.glyphId());
// restore the user coordinate system
if (nCurrentTextAngle)
{
PSGRestore ();
mnTextAngle = nCurrentTextAngle;
}
}
/*
* spool the converted truetype fonts to the page header after the page body is
* complete
* for Type1 fonts spool additional reencoding vectors that are necessary to access the
* whole font
*/
void
PrinterGfx::OnEndJob ()
{
maPS3Font.clear();
}
void
PrinterGfx::writeResources( osl::File* pFile, std::vector< OString >& rSuppliedFonts )
{
// write glyphsets and reencodings
for (auto & PS3Font : maPS3Font)
{
PS3Font.PSUploadFont (*pFile, *this, mbUploadPS42Fonts, rSuppliedFonts );
}
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */