summaryrefslogtreecommitdiff
path: root/vcl/unx/generic/printergfx
diff options
context:
space:
mode:
Diffstat (limited to 'vcl/unx/generic/printergfx')
-rw-r--r--vcl/unx/generic/printergfx/bitmap_gfx.cxx732
-rw-r--r--vcl/unx/generic/printergfx/common_gfx.cxx1284
-rw-r--r--vcl/unx/generic/printergfx/glyphset.cxx942
-rw-r--r--vcl/unx/generic/printergfx/glyphset.hxx135
-rw-r--r--vcl/unx/generic/printergfx/printerjob.cxx1204
-rw-r--r--vcl/unx/generic/printergfx/psheader.ps368
-rw-r--r--vcl/unx/generic/printergfx/psputil.cxx268
-rw-r--r--vcl/unx/generic/printergfx/psputil.hxx78
-rw-r--r--vcl/unx/generic/printergfx/text_gfx.cxx862
9 files changed, 5873 insertions, 0 deletions
diff --git a/vcl/unx/generic/printergfx/bitmap_gfx.cxx b/vcl/unx/generic/printergfx/bitmap_gfx.cxx
new file mode 100644
index 000000000000..9275db1e469f
--- /dev/null
+++ b/vcl/unx/generic/printergfx/bitmap_gfx.cxx
@@ -0,0 +1,732 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "psputil.hxx"
+
+#include "printergfx.hxx"
+#include "vcl/strhelper.hxx"
+
+namespace psp {
+
+const sal_uInt32 nLineLength = 80;
+const sal_uInt32 nBufferSize = 16384;
+
+/*
+ *
+ * Bitmap compression / Hex encoding / Ascii85 Encoding
+ *
+ */
+
+PrinterBmp::~PrinterBmp ()
+{ /* dont need this, but C50 does */ }
+
+/* virtual base class */
+
+class ByteEncoder
+{
+private:
+
+public:
+
+ virtual void EncodeByte (sal_uInt8 nByte) = 0;
+ virtual ~ByteEncoder () = 0;
+};
+
+ByteEncoder::~ByteEncoder ()
+{ /* dont need this, but the C50 does */ }
+
+/* HexEncoder */
+
+class HexEncoder : public ByteEncoder
+{
+private:
+
+ osl::File* mpFile;
+ sal_uInt32 mnColumn;
+ sal_uInt32 mnOffset;
+ sal_Char mpFileBuffer[nBufferSize + 16];
+
+ HexEncoder (); /* dont use */
+
+public:
+
+ HexEncoder (osl::File* pFile);
+ virtual ~HexEncoder ();
+ void WriteAscii (sal_uInt8 nByte);
+ virtual 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 + mnOffset);
+ mnColumn += nOff;
+ mnOffset += nOff;
+
+ if (mnColumn >= nLineLength)
+ {
+ mnOffset += psp::appendStr ("\n", mpFileBuffer + mnOffset);
+ mnColumn = 0;
+ }
+ if (mnOffset >= nBufferSize)
+ FlushLine ();
+}
+
+void
+HexEncoder::EncodeByte (sal_uInt8 nByte)
+{
+ WriteAscii (nByte);
+}
+
+void
+HexEncoder::FlushLine ()
+{
+ if (mnOffset > 0)
+ {
+ WritePS (mpFile, mpFileBuffer, mnOffset);
+ mnOffset = 0;
+ }
+}
+
+/* Ascii85 encoder, is abi compatible with HexEncoder but writes a ~> to
+ indicate end of data EOD */
+
+class Ascii85Encoder : public ByteEncoder
+{
+private:
+
+ osl::File* mpFile;
+ sal_uInt32 mnByte;
+ sal_uInt8 mpByteBuffer[4];
+
+ sal_uInt32 mnColumn;
+ sal_uInt32 mnOffset;
+ sal_Char mpFileBuffer[nBufferSize + 16];
+
+ Ascii85Encoder (); /* dont use */
+
+ inline void PutByte (sal_uInt8 nByte);
+ inline void PutEOD ();
+ void ConvertToAscii85 ();
+ void FlushLine ();
+
+public:
+
+ 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 ()
+{
+ 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 [mnOffset] = 'z';
+
+ mnOffset += 1;
+ mnColumn += 1;
+ }
+ else
+ {
+ /* real ascii85 encoding */
+ mpFileBuffer [mnOffset + 4] = (nByteValue % 85) + 33;
+ nByteValue /= 85;
+ mpFileBuffer [mnOffset + 3] = (nByteValue % 85) + 33;
+ nByteValue /= 85;
+ mpFileBuffer [mnOffset + 2] = (nByteValue % 85) + 33;
+ nByteValue /= 85;
+ mpFileBuffer [mnOffset + 1] = (nByteValue % 85) + 33;
+ nByteValue /= 85;
+ mpFileBuffer [mnOffset + 0] = (nByteValue % 85) + 33;
+
+ mnColumn += (mnByte + 1);
+ mnOffset += (mnByte + 1);
+
+ /* insert a newline if necessary */
+ if (mnColumn > nLineLength)
+ {
+ sal_uInt32 nEolOff = mnColumn - nLineLength;
+ sal_uInt32 nBufOff = mnOffset - nEolOff;
+
+ std::memmove (mpFileBuffer + nBufOff + 1, mpFileBuffer + nBufOff, nEolOff);
+ mpFileBuffer[ nBufOff ] = '\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 + mnOffset);
+ mnColumn = 0;
+ }
+ if (mnOffset >= nBufferSize)
+ FlushLine ();
+}
+
+void
+Ascii85Encoder::EncodeByte (sal_uInt8 nByte)
+{
+ WriteAscii (nByte);
+}
+
+void
+Ascii85Encoder::FlushLine ()
+{
+ if (mnOffset > 0)
+ {
+ WritePS (mpFile, mpFileBuffer, mnOffset);
+ mnOffset = 0;
+ }
+}
+
+Ascii85Encoder::~Ascii85Encoder ()
+{
+ if (mnByte > 0)
+ ConvertToAscii85 ();
+ if (mnOffset > 0)
+ FlushLine ();
+ PutEOD ();
+}
+
+/* LZW encoder */
+
+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
+ };
+
+ LZWCTreeNode* mpTable; // LZW compression data
+ LZWCTreeNode* mpPrefix; // the compression is as same as the TIFF compression
+ sal_uInt16 mnDataSize;
+ sal_uInt16 mnClearCode;
+ sal_uInt16 mnEOICode;
+ sal_uInt16 mnTableSize;
+ sal_uInt16 mnCodeSize;
+ sal_uInt32 mnOffset;
+ sal_uInt32 mdwShift;
+
+ LZWEncoder ();
+ void WriteBits (sal_uInt16 nCode, sal_uInt16 nCodeLen);
+
+public:
+
+ LZWEncoder (osl::File* pOutputFile);
+ ~LZWEncoder ();
+
+ virtual void EncodeByte (sal_uInt8 nByte);
+};
+
+LZWEncoder::LZWEncoder(osl::File* pOutputFile) :
+ Ascii85Encoder (pOutputFile)
+{
+ mnDataSize = 8;
+
+ mnClearCode = 1 << mnDataSize;
+ mnEOICode = mnClearCode + 1;
+ mnTableSize = mnEOICode + 1;
+ mnCodeSize = mnDataSize + 1;
+
+ mnOffset = 32; // free bits in dwShift
+ mdwShift = 0;
+
+ mpTable = new LZWCTreeNode[ 4096 ];
+
+ for (sal_uInt32 i = 0; i < 4096; i++)
+ {
+ mpTable[i].mpBrother = NULL;
+ mpTable[i].mpFirstChild = NULL;
+ mpTable[i].mnCode = i;
+ mpTable[i].mnValue = (sal_uInt8)mpTable[i].mnCode;
+ }
+
+ mpPrefix = NULL;
+
+ WriteBits( mnClearCode, mnCodeSize );
+}
+
+LZWEncoder::~LZWEncoder()
+{
+ if (mpPrefix)
+ WriteBits (mpPrefix->mnCode, mnCodeSize);
+
+ WriteBits (mnEOICode, mnCodeSize);
+
+ delete[] mpTable;
+}
+
+void
+LZWEncoder::WriteBits (sal_uInt16 nCode, sal_uInt16 nCodeLen)
+{
+ mdwShift |= (nCode << (mnOffset - nCodeLen));
+ mnOffset -= nCodeLen;
+ while (mnOffset < 24)
+ {
+ WriteAscii ((sal_uInt8)(mdwShift >> 24));
+ mdwShift <<= 8;
+ mnOffset += 8;
+ }
+ if (nCode == 257 && mnOffset != 32)
+ WriteAscii ((sal_uInt8)(mdwShift >> 24));
+}
+
+void
+LZWEncoder::EncodeByte (sal_uInt8 nByte )
+{
+ LZWCTreeNode* p;
+ sal_uInt16 i;
+ sal_uInt8 nV;
+
+ if (!mpPrefix)
+ {
+ mpPrefix = mpTable + nByte;
+ }
+ else
+ {
+ nV = nByte;
+ for (p = mpPrefix->mpFirstChild; p != NULL; p = p->mpBrother)
+ {
+ if (p->mnValue == nV)
+ break;
+ }
+
+ if (p != NULL)
+ {
+ mpPrefix = p;
+ }
+ else
+ {
+ WriteBits (mpPrefix->mnCode, mnCodeSize);
+
+ if (mnTableSize == 409)
+ {
+ WriteBits (mnClearCode, mnCodeSize);
+
+ for (i = 0; i < mnClearCode; i++)
+ mpTable[i].mpFirstChild = NULL;
+
+ mnCodeSize = mnDataSize + 1;
+ mnTableSize = mnEOICode + 1;
+ }
+ else
+ {
+ if(mnTableSize == (sal_uInt16)((1 << mnCodeSize) - 1))
+ mnCodeSize++;
+
+ p = mpTable + (mnTableSize++);
+ p->mpBrother = mpPrefix->mpFirstChild;
+ mpPrefix->mpFirstChild = p;
+ p->mnValue = nV;
+ p->mpFirstChild = NULL;
+ }
+
+ mpPrefix = mpTable + nV;
+ }
+ }
+}
+
+/*
+ *
+ * bitmap handling routines
+ *
+ */
+
+void
+PrinterGfx::DrawBitmap (const Rectangle& rDest, const Rectangle& rSrc,
+ const PrinterBmp& rBitmap)
+{
+ double fScaleX = (double)rDest.GetWidth() / (double)rSrc.GetWidth();
+ double fScaleY = (double)rDest.GetHeight() / (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 ();
+}
+
+/* XXX does not work XXX */
+void
+PrinterGfx::DrawBitmap (const Rectangle& rDest, const Rectangle& rSrc,
+ const PrinterBmp& /*rBitmap*/, const PrinterBmp& /*rTransBitmap*/)
+{
+ double fScaleX = (double)rDest.GetWidth() / (double)rSrc.GetWidth();
+ double fScaleY = (double)rDest.GetHeight() / (double)rSrc.GetHeight();
+
+ PSGSave ();
+ PSTranslate (rDest.BottomLeft());
+ PSScale (fScaleX, fScaleY);
+ PSGRestore ();
+}
+
+/* XXX does not work XXX */
+void
+PrinterGfx::DrawMask (const Rectangle& rDest, const Rectangle& rSrc,
+ const PrinterBmp &/*rBitmap*/, PrinterColor& /*rMaskColor*/)
+{
+ double fScaleX = (double)rDest.GetWidth() / (double)rSrc.GetWidth();
+ double fScaleY = (double)rDest.GetHeight() / (double)rSrc.GetHeight();
+
+ PSGSave ();
+ PSTranslate (rDest.BottomLeft());
+ PSScale (fScaleX, fScaleY);
+ PSGRestore ();
+}
+
+/*
+ *
+ * Implementation: PS Level 1
+ *
+ */
+
+void
+PrinterGfx::DrawPS1GrayImage (const PrinterBmp& rBitmap, const Rectangle& rArea)
+{
+ sal_uInt32 nWidth = rArea.GetWidth();
+ sal_uInt32 nHeight = rArea.GetHeight();
+
+ sal_Char pGrayImage [512];
+ sal_Int32 nChar = 0;
+
+ // image header
+ nChar += psp::getValueOf (nWidth, pGrayImage + nChar);
+ nChar += psp::appendStr (" ", pGrayImage + nChar);
+ nChar += psp::getValueOf (nHeight, pGrayImage + nChar);
+ nChar += psp::appendStr (" 8 ", pGrayImage + nChar);
+ nChar += psp::appendStr ("[ 1 0 0 1 0 ", pGrayImage + nChar);
+ nChar += psp::getValueOf (nHeight, pGrayImage + nChar);
+ nChar += psp::appendStr ("]", pGrayImage + nChar);
+ nChar += psp::appendStr (" {currentfile ", pGrayImage + nChar);
+ nChar += psp::getValueOf (nWidth, pGrayImage + nChar);
+ nChar += psp::appendStr (" string readhexstring pop}\n", pGrayImage + nChar);
+ nChar += psp::appendStr ("image\n", pGrayImage + nChar);
+
+ WritePS (mpPageBody, pGrayImage);
+
+ // image body
+ HexEncoder* pEncoder = new HexEncoder (mpPageBody);
+
+ for (long nRow = rArea.Top(); nRow <= rArea.Bottom(); nRow++)
+ {
+ for (long nColumn = rArea.Left(); nColumn <= rArea.Right(); nColumn++)
+ {
+ sal_uChar nByte = rBitmap.GetPixelGray (nRow, nColumn);
+ pEncoder->EncodeByte (nByte);
+ }
+ }
+
+ delete pEncoder;
+
+ WritePS (mpPageBody, "\n");
+}
+
+/*
+ *
+ * Implementation: PS Level 2
+ *
+ */
+
+void
+PrinterGfx::writePS2ImageHeader (const Rectangle& rArea, psp::ImageType nType)
+{
+ sal_Int32 nChar = 0;
+ sal_Char pImage [512];
+
+ sal_Int32 nDictType = 0;
+ switch (nType)
+ {
+ case psp::TrueColorImage: nDictType = 0; break;
+ case psp::PaletteImage: nDictType = 1; break;
+ case psp::GrayScaleImage: nDictType = 2; break;
+ case psp::MonochromeImage: nDictType = 3; break;
+ default: break;
+ }
+ sal_Int32 nCompressType = mbCompressBmp ? 1 : 0;
+
+ nChar += psp::getValueOf (rArea.GetWidth(), pImage + nChar);
+ nChar += psp::appendStr (" ", pImage + nChar);
+ nChar += psp::getValueOf (rArea.GetHeight(), pImage + nChar);
+ nChar += psp::appendStr (" ", pImage + nChar);
+ nChar += psp::getValueOf (nDictType, pImage + nChar);
+ nChar += psp::appendStr (" ", pImage + nChar);
+ nChar += psp::getValueOf (nCompressType, pImage + nChar);
+ nChar += psp::appendStr (" psp_imagedict image\n", pImage + nChar);
+
+ WritePS (mpPageBody, pImage);
+}
+
+void
+PrinterGfx::writePS2Colorspace(const PrinterBmp& rBitmap, psp::ImageType nType)
+{
+ switch (nType)
+ {
+ case psp::GrayScaleImage:
+
+ WritePS (mpPageBody, "/DeviceGray setcolorspace\n");
+ break;
+
+ case psp::TrueColorImage:
+
+ WritePS (mpPageBody, "/DeviceRGB setcolorspace\n");
+ break;
+
+ case psp::MonochromeImage:
+ case psp::PaletteImage:
+ {
+
+ sal_Int32 nChar = 0;
+ sal_Char pImage [4096];
+
+ const sal_uInt32 nSize = rBitmap.GetPaletteEntryCount();
+
+ nChar += psp::appendStr ("[/Indexed /DeviceRGB ", pImage + nChar);
+ nChar += psp::getValueOf (nSize - 1, pImage + nChar);
+ if (mbCompressBmp)
+ nChar += psp::appendStr ("\npsp_lzwstring\n", pImage + nChar);
+ else
+ nChar += psp::appendStr ("\npsp_ascii85string\n", pImage + nChar);
+ WritePS (mpPageBody, pImage);
+
+ ByteEncoder* pEncoder = mbCompressBmp ? new LZWEncoder(mpPageBody)
+ : new Ascii85Encoder(mpPageBody);
+ for (sal_uInt32 i = 0; i < nSize; i++)
+ {
+ PrinterColor aColor = rBitmap.GetPaletteColor(i);
+
+ pEncoder->EncodeByte (aColor.GetRed());
+ pEncoder->EncodeByte (aColor.GetGreen());
+ pEncoder->EncodeByte (aColor.GetBlue());
+ }
+ delete pEncoder;
+
+ WritePS (mpPageBody, "pop ] setcolorspace\n");
+ }
+ break;
+ default: break;
+ }
+}
+
+void
+PrinterGfx::DrawPS2GrayImage (const PrinterBmp& rBitmap, const Rectangle& rArea)
+{
+ writePS2Colorspace(rBitmap, psp::GrayScaleImage);
+ writePS2ImageHeader(rArea, psp::GrayScaleImage);
+
+ ByteEncoder* pEncoder = mbCompressBmp ? new LZWEncoder(mpPageBody)
+ : new Ascii85Encoder(mpPageBody);
+
+ for (long nRow = rArea.Top(); nRow <= rArea.Bottom(); nRow++)
+ {
+ for (long nColumn = rArea.Left(); nColumn <= rArea.Right(); nColumn++)
+ {
+ sal_uChar nByte = rBitmap.GetPixelGray (nRow, nColumn);
+ pEncoder->EncodeByte (nByte);
+ }
+ }
+
+ delete pEncoder;
+}
+
+void
+PrinterGfx::DrawPS2MonoImage (const PrinterBmp& rBitmap, const Rectangle& rArea)
+{
+ writePS2Colorspace(rBitmap, psp::MonochromeImage);
+ writePS2ImageHeader(rArea, psp::MonochromeImage);
+
+ ByteEncoder* pEncoder = mbCompressBmp ? new LZWEncoder(mpPageBody)
+ : new Ascii85Encoder(mpPageBody);
+
+ for (long nRow = rArea.Top(); nRow <= rArea.Bottom(); nRow++)
+ {
+ long nBitPos = 0;
+ sal_uChar nBit = 0;
+ sal_uChar nByte = 0;
+
+ for (long nColumn = rArea.Left(); nColumn <= rArea.Right(); nColumn++)
+ {
+ nBit = rBitmap.GetPixelIdx (nRow, nColumn);
+ nByte |= nBit << (7 - nBitPos);
+
+ if (++nBitPos == 8)
+ {
+ pEncoder->EncodeByte (nByte);
+ nBitPos = 0;
+ nByte = 0;
+ }
+ }
+ // keep the row byte aligned
+ if (nBitPos != 0)
+ pEncoder->EncodeByte (nByte);
+ }
+
+ delete pEncoder;
+}
+
+void
+PrinterGfx::DrawPS2PaletteImage (const PrinterBmp& rBitmap, const Rectangle& rArea)
+{
+ writePS2Colorspace(rBitmap, psp::PaletteImage);
+ writePS2ImageHeader(rArea, psp::PaletteImage);
+
+ ByteEncoder* pEncoder = mbCompressBmp ? new LZWEncoder(mpPageBody)
+ : new Ascii85Encoder(mpPageBody);
+
+ for (long nRow = rArea.Top(); nRow <= rArea.Bottom(); nRow++)
+ {
+ for (long nColumn = rArea.Left(); nColumn <= rArea.Right(); nColumn++)
+ {
+ sal_uChar nByte = rBitmap.GetPixelIdx (nRow, nColumn);
+ pEncoder->EncodeByte (nByte);
+ }
+ }
+
+ delete pEncoder;
+}
+
+void
+PrinterGfx::DrawPS2TrueColorImage (const PrinterBmp& rBitmap, const Rectangle& rArea)
+{
+ writePS2Colorspace(rBitmap, psp::TrueColorImage);
+ writePS2ImageHeader(rArea, psp::TrueColorImage);
+
+ ByteEncoder* pEncoder = mbCompressBmp ? new LZWEncoder(mpPageBody)
+ : new Ascii85Encoder(mpPageBody);
+
+ for (long nRow = rArea.Top(); nRow <= rArea.Bottom(); nRow++)
+ {
+ for (long nColumn = rArea.Left(); nColumn <= rArea.Right(); nColumn++)
+ {
+ PrinterColor aColor = rBitmap.GetPixelRGB (nRow, nColumn);
+ pEncoder->EncodeByte (aColor.GetRed());
+ pEncoder->EncodeByte (aColor.GetGreen());
+ pEncoder->EncodeByte (aColor.GetBlue());
+ }
+ }
+
+ delete pEncoder;
+}
+
+} /* namespace psp */
diff --git a/vcl/unx/generic/printergfx/common_gfx.cxx b/vcl/unx/generic/printergfx/common_gfx.cxx
new file mode 100644
index 000000000000..6ebf79cfac73
--- /dev/null
+++ b/vcl/unx/generic/printergfx/common_gfx.cxx
@@ -0,0 +1,1284 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "psputil.hxx"
+#include "glyphset.hxx"
+
+#include "printergfx.hxx"
+#include "printerjob.hxx"
+#include "vcl/fontmanager.hxx"
+#include "vcl/strhelper.hxx"
+#include "vcl/printerinfomanager.hxx"
+
+#include "tools/debug.hxx"
+#include "tools/color.hxx"
+#include "tools/poly.hxx"
+
+using namespace psp ;
+
+static const sal_Int32 nMaxTextColumn = 80;
+
+GraphicsStatus::GraphicsStatus() :
+ mbArtItalic( false ),
+ mbArtBold( false ),
+ mnTextHeight( 0 ),
+ mnTextWidth( 0 ),
+ mfLineWidth( -1 )
+{
+}
+
+/*
+ * non graphics graphics routines
+ */
+
+sal_Bool
+PrinterGfx::Init (PrinterJob &rPrinterJob)
+{
+ mpPageHeader = rPrinterJob.GetCurrentPageHeader ();
+ 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() ) );
+ if( mpFontSubstitutes )
+ delete const_cast< ::std::hash_map<fontID,fontID>* >(mpFontSubstitutes);
+ if( rInfo.m_bPerformFontSubstitution )
+ mpFontSubstitutes = new ::std::hash_map< fontID, fontID >( rInfo.m_aFontSubstitutions );
+ else
+ mpFontSubstitutes = NULL;
+ mbUploadPS42Fonts = rInfo.m_pParser ? ( rInfo.m_pParser->isType42Capable() ? sal_True : sal_False ) : sal_False;
+
+ return sal_True;
+}
+
+sal_Bool
+PrinterGfx::Init (const JobData& rData)
+{
+ mpPageHeader = NULL;
+ mpPageBody = NULL;
+ 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 ? sal_False : sal_True ) : (( rData.m_pParser ? (rData.m_pParser->isColorDevice() ? sal_True : sal_False ) : sal_True ) );
+ int nRes = rData.m_aContext.getRenderResolution();
+ mnDpi = nRes;
+ mfScaleX = (double)72.0 / (double)mnDpi;
+ mfScaleY = (double)72.0 / (double)mnDpi;
+ const PrinterInfo& rInfo( PrinterInfoManager::get().getPrinterInfo( rData.m_aPrinterName ) );
+ if( mpFontSubstitutes )
+ delete const_cast< ::std::hash_map<fontID,fontID>* >(mpFontSubstitutes);
+ if( rInfo.m_bPerformFontSubstitution )
+ mpFontSubstitutes = new ::std::hash_map< fontID, fontID >( rInfo.m_aFontSubstitutions );
+ else
+ mpFontSubstitutes = NULL;
+ mbUploadPS42Fonts = rInfo.m_pParser ? ( rInfo.m_pParser->isType42Capable() ? sal_True : sal_False ) : sal_False;
+
+ return sal_True;
+}
+
+void
+PrinterGfx::GetResolution (sal_Int32 &rDpiX, sal_Int32 &rDpiY) const
+{
+ rDpiX = mnDpi;
+ rDpiY = mnDpi;
+}
+
+sal_uInt16
+PrinterGfx::GetBitCount ()
+{
+ return mnDepth;
+}
+
+PrinterGfx::PrinterGfx() :
+ mpPageHeader (NULL),
+ mpPageBody (NULL),
+ mnFontID (0),
+ mnFallbackID (0),
+ mnTextAngle (0),
+ mbTextVertical (false),
+ mrFontMgr (PrintFontManager::get()),
+ mbCompressBmp (sal_True),
+ maFillColor (0xff,0,0),
+ maTextColor (0,0,0),
+ maLineColor (0, 0xff, 0),
+ mpFontSubstitutes( NULL ),
+ mbStrictSO52Compatibility( false )
+{
+ maVirtualStatus.mfLineWidth = 1.0;
+ maVirtualStatus.mnTextHeight = 12;
+ maVirtualStatus.mnTextWidth = 0;
+
+ maGraphicsStack.push_back( GraphicsStatus() );
+}
+
+PrinterGfx::~PrinterGfx()
+{
+ /*
+ * #95810# the original reasoning why mpFontSubstitutes is a pointer was
+ * that applications should release all PrinterGfx when printers change
+ * because they are really invalid; the corresponding printers may have
+ * changed their settings or even not exist anymore.
+ *
+ * Alas, this is not always done real time. So we keep a local copy of
+ * the font substitutes now in case of bad timing.
+ */
+ delete const_cast< ::std::hash_map<fontID,fontID>* >(mpFontSubstitutes);
+}
+
+void
+PrinterGfx::Clear()
+{
+ mpPageHeader = NULL;
+ mpPageBody = NULL;
+ mnFontID = 0;
+ maVirtualStatus = GraphicsStatus();
+ maVirtualStatus.mnTextHeight = 12;
+ maVirtualStatus.mnTextWidth = 0;
+ maVirtualStatus.mfLineWidth = 1.0;
+ mbTextVertical = false;
+ maLineColor = PrinterColor();
+ maFillColor = PrinterColor();
+ maTextColor = PrinterColor();
+ mbCompressBmp = sal_True;
+ mnDpi = 300;
+ mnDepth = 24;
+ mnPSLevel = 2;
+ mbColor = sal_True;
+ mnTextAngle = 0;
+
+ maClipRegion.clear();
+ maGraphicsStack.clear();
+ maGraphicsStack.push_back( GraphicsStatus() );
+}
+
+/*
+ * clip region handling
+ */
+
+void
+PrinterGfx::ResetClipRegion()
+{
+ maClipRegion.clear();
+ PSGRestore ();
+ PSGSave (); // get "clean" clippath
+}
+
+void
+PrinterGfx::BeginSetClipRegion( sal_uInt32 )
+{
+ maClipRegion.clear();
+}
+
+sal_Bool
+PrinterGfx::UnionClipRegion (sal_Int32 nX,sal_Int32 nY,sal_Int32 nDX,sal_Int32 nDY)
+{
+ if( nDX && nDY )
+ maClipRegion.push_back (Rectangle(Point(nX,nY ), Size(nDX,nDY)));
+ return sal_True;
+}
+
+sal_Bool
+PrinterGfx::JoinVerticalClipRectangles( std::list< Rectangle >::iterator& it,
+ Point& rOldPoint, sal_Int32& rColumn )
+{
+ sal_Bool bSuccess = sal_False;
+
+ std::list< Rectangle >::iterator tempit, nextit;
+ nextit = it;
+ ++nextit;
+ std::list< Point > leftside, rightside;
+
+ Rectangle aLastRect( *it );
+ leftside.push_back( Point( it->Left(), it->Top() ) );
+ rightside.push_back( Point( 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 ||
+ abs( aLastRect.Left() - nextit->Left() ) > 2 ||
+ abs( aLastRect.Right() - nextit->Right() ) > 2
+ )
+ {
+ leftside.push_back( Point( aLastRect.Left(), aLastRect.Bottom()+1 ) );
+ rightside.push_back( Point( 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.push_back( Point( aLastRect.Left(), aLastRect.Bottom()+1 ) );
+ rightside.push_back( Point( aLastRect.Right()+1, aLastRect.Bottom()+1 ) );
+
+ // cool, we can concatenate rectangles
+ int nDX = -65536, nDY = 65536;
+ int nNewDX = 0, nNewDY = 0;
+
+ Point aLastPoint = leftside.front();
+ PSBinMoveTo (aLastPoint, rOldPoint, rColumn);
+ leftside.pop_front();
+ while( leftside.begin() != leftside.end() )
+ {
+ Point aPoint (leftside.front());
+ leftside.pop_front();
+ // may have been the last one
+ if( leftside.begin() != leftside.end() )
+ {
+ nNewDX = aPoint.X() - aLastPoint.X();
+ nNewDY = aPoint.Y() - aLastPoint.Y();
+ if( nNewDX == 0 && nDX == 0 )
+ continue;
+ if( nDX != 0 && nNewDX != 0 &&
+ (double)nNewDY/(double)nNewDX == (double)nDY/(double)nDX )
+ continue;
+ }
+ PSBinLineTo (aPoint, rOldPoint, rColumn);
+ aLastPoint = aPoint;
+ }
+
+ aLastPoint = rightside.back();
+ nDX = -65536;
+ nDY = 65536;
+ PSBinLineTo (aLastPoint, rOldPoint, rColumn);
+ rightside.pop_back();
+ while( rightside.begin() != rightside.end() )
+ {
+ Point aPoint (rightside.back());
+ rightside.pop_back();
+ if( rightside.begin() != rightside.end() )
+ {
+ nNewDX = aPoint.X() - aLastPoint.X();
+ nNewDY = aPoint.Y() - aLastPoint.Y();
+ if( nNewDX == 0 && nDX == 0 )
+ continue;
+ if( nDX != 0 && nNewDX != 0 &&
+ (double)nNewDY/(double)nNewDX == (double)nDY/(double)nDX )
+ continue;
+ }
+ PSBinLineTo (aPoint, rOldPoint, rColumn);
+ }
+
+ tempit = it;
+ ++tempit;
+ maClipRegion.erase( it );
+ it = tempit;
+ bSuccess = sal_True;
+ }
+ return bSuccess;
+}
+
+void
+PrinterGfx::EndSetClipRegion()
+{
+ PSGRestore ();
+ PSGSave (); // get "clean" clippath
+
+ PSBinStartPath ();
+ Point aOldPoint (0, 0);
+ sal_Int32 nColumn = 0;
+
+ std::list< 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 (it->TopLeft(), aOldPoint, nColumn );
+ PSBinLineTo (Point( it->Left(), it->Bottom()+1 ), aOldPoint, nColumn );
+ PSBinLineTo (Point( it->Right()+1, it->Bottom()+1 ), aOldPoint, nColumn );
+ PSBinLineTo (Point( it->Right()+1, it->Top() ), aOldPoint, nColumn );
+ ++it;
+ }
+ }
+
+ PSBinEndPath ();
+
+ WritePS (mpPageBody, "closepath clip newpath\n");
+ maClipRegion.clear();
+}
+
+/*
+ * draw graphic primitives
+ */
+
+void
+PrinterGfx::DrawRect (const Rectangle& rRectangle )
+{
+ char pRect [128];
+ sal_Int32 nChar = 0;
+
+ nChar = psp::getValueOf (rRectangle.TopLeft().X(), pRect);
+ nChar += psp::appendStr (" ", pRect + nChar);
+ nChar += psp::getValueOf (rRectangle.TopLeft().Y(), pRect + nChar);
+ nChar += psp::appendStr (" ", pRect + nChar);
+ nChar += psp::getValueOf (rRectangle.GetWidth(), pRect + nChar);
+ nChar += psp::appendStr (" ", pRect + nChar);
+ nChar += psp::getValueOf (rRectangle.GetHeight(), pRect + nChar);
+ nChar += psp::appendStr (" ", pRect + nChar);
+
+ if( maFillColor.Is() )
+ {
+ PSSetColor (maFillColor);
+ PSSetColor ();
+ WritePS (mpPageBody, pRect, nChar);
+ WritePS (mpPageBody, "rectfill\n");
+ }
+ if( maLineColor.Is() )
+ {
+ PSSetColor (maLineColor);
+ PSSetColor ();
+ PSSetLineWidth ();
+ WritePS (mpPageBody, pRect, nChar);
+ 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 > 1) || (pPath == NULL) || !(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 sal_uInt8* pFlgAry)
+{
+ const sal_uInt32 nBezString= 1024;
+ sal_Char pString[nBezString];
+
+ if ( nPoints > 1 && maLineColor.Is() && pPath )
+ {
+ PSSetColor (maLineColor);
+ PSSetColor ();
+ PSSetLineWidth ();
+
+ snprintf(pString, nBezString, "%li %li moveto\n", pPath[0].X(), 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] != POLY_CONTROL) //If the next point is a POLY_NORMAL, we're drawing a line
+ {
+ snprintf(pString, nBezString, "%li %li lineto\n", pPath[i].X(), pPath[i].Y());
+ i++;
+ }
+ else //Otherwise we're drawing a spline
+ {
+ if (i+2 >= nPoints)
+ return; //Error: wrong sequence of contol/normal points somehow
+ if ((pFlgAry[i] == POLY_CONTROL) && (pFlgAry[i+1] == POLY_CONTROL) &&
+ (pFlgAry[i+2] != POLY_CONTROL))
+ {
+ snprintf(pString, nBezString, "%li %li %li %li %li %li curveto\n",
+ pPath[i].X(), pPath[i].Y(),
+ pPath[i+1].X(), pPath[i+1].Y(),
+ pPath[i+2].X(), pPath[i+2].Y());
+ }
+ else
+ {
+ DBG_ERROR( "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 sal_uInt8* pFlgAry)
+{
+ const sal_uInt32 nBezString = 1024;
+ sal_Char pString[nBezString];
+ // premature end of operation
+ if (!(nPoints > 1) || (pPath == NULL) || !(maFillColor.Is() || maLineColor.Is()))
+ return;
+
+ snprintf(pString, nBezString, "%li %li moveto\n", pPath[0].X(), pPath[0].Y());
+ WritePS(mpPageBody, pString); //Move to the starting point for the PolyPoygon
+ for (unsigned int i=1; i < nPoints;)
+ {
+ if (pFlgAry[i] != POLY_CONTROL)
+ {
+ snprintf(pString, nBezString, "%li %li lineto\n", pPath[i].X(), pPath[i].Y());
+ WritePS(mpPageBody, pString);
+ i++;
+ }
+ else
+ {
+ if (i+2 >= nPoints)
+ return; //Error: wrong sequence of contol/normal points somehow
+ if ((pFlgAry[i] == POLY_CONTROL) && (pFlgAry[i+1] == POLY_CONTROL) &&
+ (pFlgAry[i+2] != POLY_CONTROL))
+ {
+ snprintf(pString, nBezString, "%li %li %li %li %li %li curveto\n",
+ pPath[i].X(), pPath[i].Y(),
+ pPath[i+1].X(), pPath[i+1].Y(),
+ pPath[i+2].X(), pPath[i+2].Y());
+ WritePS(mpPageBody, pString);
+ }
+ else
+ {
+ DBG_ERROR( "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 sal_uInt8* const* pFlgAry)
+{
+ const sal_uInt32 nBezString = 1024;
+ sal_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];
+ // #112689# sanity check
+ if( nPoints == 0 || pPtAry[i] == NULL )
+ continue;
+
+ snprintf(pString, nBezString, "%li %li moveto\n", pPtAry[i][0].X(), 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] != POLY_CONTROL)
+ {
+ snprintf(pString, nBezString, "%li %li lineto\n", pPtAry[i][j].X(), pPtAry[i][j].Y());
+ WritePS(mpPageBody, pString);
+ j++;
+ }
+ else
+ {
+ if (j+2 >= nPoints)
+ break; //Error: wrong sequence of contol/normal points somehow
+ if ((pFlgAry[i][j] == POLY_CONTROL) && (pFlgAry[i][j+1] == POLY_CONTROL) && (pFlgAry[i][j+2] != POLY_CONTROL))
+ {
+ snprintf(pString, nBezString, "%li %li %li %li %li %li curveto\n",
+ pPtAry[i][j].X(), pPtAry[i][j].Y(),
+ pPtAry[i][j+1].X(), pPtAry[i][j+1].Y(),
+ pPtAry[i][j+2].X(), pPtAry[i][j+2].Y());
+ WritePS(mpPageBody, pString);
+ }
+ else
+ {
+ DBG_ERROR( "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.begin() != maGraphicsStack.end() )
+ aNewState = maGraphicsStack.front();
+ maGraphicsStack.push_front( aNewState );
+}
+
+void
+PrinterGfx::PSGRestore ()
+{
+ WritePS (mpPageBody, "grestore\n" );
+ if( maGraphicsStack.begin() == maGraphicsStack.end() )
+ WritePS (mpPageBody, "Error: too many grestores\n" );
+ else
+ maGraphicsStack.pop_front();
+}
+
+void
+PrinterGfx::PSSetLineWidth ()
+{
+ if( currentState().mfLineWidth != maVirtualStatus.mfLineWidth )
+ {
+ char pBuffer[128];
+ sal_Int32 nChar = 0;
+
+ currentState().mfLineWidth = maVirtualStatus.mfLineWidth;
+ nChar = psp::getValueOfDouble (pBuffer, maVirtualStatus.mfLineWidth, 5);
+ nChar += psp::appendStr (" setlinewidth\n", pBuffer + nChar);
+ WritePS (mpPageBody, pBuffer, nChar);
+ }
+}
+
+void
+PrinterGfx::PSSetColor ()
+{
+ PrinterColor& rColor( maVirtualStatus.maColor );
+
+ if( currentState().maColor != rColor )
+ {
+ currentState().maColor = rColor;
+
+ char pBuffer[128];
+ sal_Int32 nChar = 0;
+
+ if( mbColor )
+ {
+ nChar = psp::getValueOfDouble (pBuffer,
+ (double)rColor.GetRed() / 255.0, 5);
+ nChar += psp::appendStr (" ", pBuffer + nChar);
+ nChar += psp::getValueOfDouble (pBuffer + nChar,
+ (double)rColor.GetGreen() / 255.0, 5);
+ nChar += psp::appendStr (" ", pBuffer + nChar);
+ nChar += psp::getValueOfDouble (pBuffer + nChar,
+ (double)rColor.GetBlue() / 255.0, 5);
+ nChar += psp::appendStr (" setrgbcolor\n", pBuffer + nChar );
+ }
+ else
+ {
+ Color aColor( rColor.GetRed(), rColor.GetGreen(), rColor.GetBlue() );
+ sal_uInt8 nCol = aColor.GetLuminance();
+ nChar = psp::getValueOfDouble( pBuffer, (double)nCol / 255.0, 5 );
+ nChar += psp::appendStr( " setgray\n", pBuffer + nChar );
+ }
+
+ WritePS (mpPageBody, pBuffer, nChar);
+ }
+}
+
+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
+ )
+ {
+ 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;
+
+ sal_Char pSetFont [256];
+ sal_Int32 nChar = 0;
+
+ // 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)
+ )
+ {
+ rtl::OString aReencodedFont =
+ psp::GlyphSet::GetReencodedFontName (rCurrent.maEncoding,
+ rCurrent.maFont);
+
+ nChar += psp::appendStr ("(", pSetFont + nChar);
+ nChar += psp::appendStr (aReencodedFont.getStr(),
+ pSetFont + nChar);
+ nChar += psp::appendStr (") cvn findfont ",
+ pSetFont + nChar);
+ }
+ else
+ // tt based fonts mustn't reencode, the encoding is implied by the fontname
+ // same for symbol type1 fonts, dont try to touch them
+ {
+ nChar += psp::appendStr ("(", pSetFont + nChar);
+ nChar += psp::appendStr (rCurrent.maFont.getStr(),
+ pSetFont + nChar);
+ nChar += psp::appendStr (") cvn findfont ",
+ pSetFont + nChar);
+ }
+
+ if( ! rCurrent.mbArtItalic )
+ {
+ nChar += psp::getValueOf (nTextWidth, pSetFont + nChar);
+ nChar += psp::appendStr (" ", pSetFont + nChar);
+ nChar += psp::getValueOf (-nTextHeight, pSetFont + nChar);
+ nChar += psp::appendStr (" matrix scale makefont setfont\n", pSetFont + nChar);
+ }
+ else // skew 15 degrees to right
+ {
+ nChar += psp::appendStr ( " [", pSetFont + nChar);
+ nChar += psp::getValueOf (nTextWidth, pSetFont + nChar);
+ nChar += psp::appendStr (" 0 ", pSetFont + nChar);
+ nChar += psp::getValueOfDouble (pSetFont + nChar, 0.27*(double)nTextWidth, 3 );
+ nChar += psp::appendStr ( " ", pSetFont + nChar);
+ nChar += psp::getValueOf (-nTextHeight, pSetFont + nChar);
+
+ nChar += psp::appendStr (" 0 0] makefont setfont\n", pSetFont + nChar);
+ }
+
+ WritePS (mpPageBody, pSetFont);
+ }
+}
+
+void
+PrinterGfx::PSRotate (sal_Int32 nAngle)
+{
+ sal_Int32 nPostScriptAngle = -nAngle;
+ while( nPostScriptAngle < 0 )
+ nPostScriptAngle += 3600;
+
+ if (nPostScriptAngle == 0)
+ return;
+
+ sal_Int32 nFullAngle = nPostScriptAngle / 10;
+ sal_Int32 nTenthAngle = nPostScriptAngle % 10;
+
+ sal_Char pRotate [48];
+ sal_Int32 nChar = 0;
+
+ nChar = psp::getValueOf (nFullAngle, pRotate);
+ nChar += psp::appendStr (".", pRotate + nChar);
+ nChar += psp::getValueOf (nTenthAngle, pRotate + nChar);
+ nChar += psp::appendStr (" rotate\n", pRotate + nChar);
+
+ WritePS (mpPageBody, pRotate);
+}
+
+void
+PrinterGfx::PSPointOp (const Point& rPoint, const sal_Char* pOperator)
+{
+ sal_Char pPSCommand [48];
+ sal_Int32 nChar = 0;
+
+ nChar = psp::getValueOf (rPoint.X(), pPSCommand);
+ nChar += psp::appendStr (" ", pPSCommand + nChar);
+ nChar += psp::getValueOf (rPoint.Y(), pPSCommand + nChar);
+ nChar += psp::appendStr (" ", pPSCommand + nChar);
+ nChar += psp::appendStr (pOperator, pPSCommand + nChar);
+ nChar += psp::appendStr ("\n", pPSCommand + nChar);
+
+ DBG_ASSERT (nChar < 48, "Buffer overflow in PSPointOp");
+
+ WritePS (mpPageBody, pPSCommand);
+}
+
+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");
+}
+
+void
+PrinterGfx::PSRMoveTo (sal_Int32 nDx, sal_Int32 nDy)
+{
+ Point aPoint(nDx, nDy);
+ PSPointOp (aPoint, "rmoveto");
+}
+
+/* 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)
+{
+ sal_Char pPath[48];
+ 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 + 1);
+ sal_Int32 nYPrec = getAlignedHexValueOf (rCurrent.Y() - rOld.Y(), pPath + 1 + nXPrec);
+ pPath [ 1 + nXPrec + nYPrec ] = 0;
+
+ // build the command, it is a char with bit represention 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
+ sal_Char cCmd = (eType == lineto ? (sal_Char)0x00 : (sal_Char)0x10);
+ switch (nYPrec)
+ {
+ case 2: break;
+ case 4: cCmd |= 0x01; break;
+ case 6: cCmd |= 0x02; break;
+ case 8: cCmd |= 0x03; break;
+ default: DBG_ERROR ("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: DBG_ERROR ("invalid y precision in binary path");
+ }
+ cCmd += 'A';
+ pPath[0] = cCmd;
+
+ // 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, pPath, nSegment);
+ WritePS (mpPageBody, "\n", 1);
+ WritePS (mpPageBody, pPath + nSegment, nChar - nSegment);
+
+ nColumn = nChar - nSegment;
+ }
+ else
+ {
+ WritePS (mpPageBody, pPath, nChar);
+
+ nColumn += nChar;
+ }
+
+ rOld = rCurrent;
+}
+
+void
+PrinterGfx::PSScale (double fScaleX, double fScaleY)
+{
+ sal_Char pScale [48];
+ sal_Int32 nChar = 0;
+
+ nChar = psp::getValueOfDouble (pScale, fScaleX, 5);
+ nChar += psp::appendStr (" ", pScale + nChar);
+ nChar += psp::getValueOfDouble (pScale + nChar, fScaleY, 5);
+ nChar += psp::appendStr (" scale\n", pScale + nChar);
+
+ WritePS (mpPageBody, pScale);
+}
+
+/* psshowtext helper routines: draw an hex string for show/xshow */
+void
+PrinterGfx::PSHexString (const sal_uChar* pString, sal_Int16 nLen)
+{
+ sal_Char pHexString [128];
+ sal_Int32 nChar = 0;
+
+ nChar = psp::appendStr ("<", pHexString);
+ for (int i = 0; i < nLen; i++)
+ {
+ if (nChar >= (nMaxTextColumn - 1))
+ {
+ nChar += psp::appendStr ("\n", pHexString + nChar);
+ WritePS (mpPageBody, pHexString, nChar);
+ nChar = 0;
+ }
+ nChar += psp::getHexValueOf ((sal_Int32)pString[i], pHexString + nChar);
+ }
+
+ nChar += psp::appendStr (">\n", pHexString + nChar);
+ WritePS (mpPageBody, pHexString, nChar);
+}
+
+/* psshowtext helper routines: draw an array for xshow ps operator */
+void
+PrinterGfx::PSDeltaArray (const sal_Int32 *pArray, sal_Int16 nEntries)
+{
+ sal_Char pPSArray [128];
+ sal_Int32 nChar = 0;
+
+ nChar = psp::appendStr ("[", pPSArray + nChar);
+ nChar += psp::getValueOf (pArray[0], pPSArray + nChar);
+
+ for (int i = 1; i < nEntries; i++)
+ {
+ if (nChar >= (nMaxTextColumn - 1))
+ {
+ nChar += psp::appendStr ("\n", pPSArray + nChar);
+ WritePS (mpPageBody, pPSArray, nChar);
+ nChar = 0;
+ }
+
+ nChar += psp::appendStr (" ", pPSArray + nChar);
+ nChar += psp::getValueOf (pArray[i] - pArray[i-1], pPSArray + nChar);
+ }
+
+ nChar += psp::appendStr (" 0]\n", pPSArray + nChar);
+ WritePS (mpPageBody, pPSArray);
+}
+
+/* the DrawText equivalent, pDeltaArray may be NULL. For Type1 fonts or single byte
+ * fonts in general nBytes and nGlyphs is the same. For printer resident Composite
+ * fonts it may be different (these fonts may be SJIS encoded for example) */
+void
+PrinterGfx::PSShowText (const sal_uChar* pStr, sal_Int16 nGlyphs, sal_Int16 nBytes,
+ const sal_Int32* pDeltaArray)
+{
+ PSSetColor (maTextColor);
+ PSSetColor ();
+ PSSetFont ();
+ // rotate the user coordinate system
+ if (mnTextAngle != 0)
+ {
+ PSGSave ();
+ PSRotate (mnTextAngle);
+ }
+
+ sal_Char pBuffer[256];
+ if( maVirtualStatus.mbArtBold )
+ {
+ sal_Int32 nLW = maVirtualStatus.mnTextWidth;
+ if( nLW == 0 )
+ nLW = maVirtualStatus.mnTextHeight;
+ else
+ nLW = nLW < maVirtualStatus.mnTextHeight ? nLW : maVirtualStatus.mnTextHeight;
+ psp::getValueOfDouble( pBuffer, (double)nLW / 30.0 );
+ }
+ // dispatch to the drawing method
+ if (pDeltaArray == NULL)
+ {
+ PSHexString (pStr, nBytes);
+
+ if( maVirtualStatus.mbArtBold )
+ {
+ WritePS( mpPageBody, pBuffer );
+ WritePS( mpPageBody, " bshow\n" );
+ }
+ else
+ WritePS (mpPageBody, "show\n");
+ }
+ else
+ {
+ PSHexString (pStr, nBytes);
+ PSDeltaArray (pDeltaArray, nGlyphs - 1);
+ if( maVirtualStatus.mbArtBold )
+ {
+ WritePS( mpPageBody, pBuffer );
+ WritePS( mpPageBody, " bxshow\n" );
+ }
+ else
+ WritePS (mpPageBody, "xshow\n");
+ }
+
+ // restore the user coordinate system
+ if (mnTextAngle != 0)
+ PSGRestore ();
+}
+
+void
+PrinterGfx::PSComment( const sal_Char* pComment )
+{
+ const sal_Char* pLast = pComment;
+ while( pComment && *pComment )
+ {
+ while( *pComment && *pComment != '\n' && *pComment != '\r' )
+ pComment++;
+ if( pComment - pLast > 1 )
+ {
+ WritePS( mpPageBody, "% ", 2 );
+ WritePS( mpPageBody, pLast, pComment - pLast );
+ WritePS( mpPageBody, "\n", 1 );
+ }
+ if( *pComment )
+ pLast = ++pComment;
+ }
+}
+
+sal_Bool
+PrinterGfx::DrawEPS( const Rectangle& rBoundingBox, void* pPtr, sal_uInt32 nSize )
+{
+ if( nSize == 0 )
+ return sal_True;
+ if( ! mpPageBody )
+ return sal_False;
+
+ sal_Bool bSuccess = sal_False;
+
+ // first search the BoundingBox of the EPS data
+ SvMemoryStream aStream( pPtr, nSize, STREAM_READ );
+ aStream.Seek( STREAM_SEEK_TO_BEGIN );
+ ByteString aLine;
+
+ ByteString aDocTitle;
+ double fLeft = 0, fRight = 0, fTop = 0, fBottom = 0;
+ bool bEndComments = false;
+ while( ! aStream.IsEof()
+ && ( ( fLeft == 0 && fRight == 0 && fTop == 0 && fBottom == 0 ) ||
+ ( aDocTitle.Len() == 0 && bEndComments == false ) )
+ )
+ {
+ aStream.ReadLine( aLine );
+ if( aLine.Len() > 1 && aLine.GetChar( 0 ) == '%' )
+ {
+ char cChar = aLine.GetChar(1);
+ if( cChar == '%' )
+ {
+ if( aLine.CompareIgnoreCaseToAscii( "%%BoundingBox:", 14 ) == COMPARE_EQUAL )
+ {
+ aLine = WhitespaceToSpace( aLine.GetToken( 1, ':' ) );
+ if( aLine.Len() && aLine.Search( "atend" ) == STRING_NOTFOUND )
+ {
+ fLeft = StringToDouble( GetCommandLineToken( 0, aLine ) );
+ fBottom = StringToDouble( GetCommandLineToken( 1, aLine ) );
+ fRight = StringToDouble( GetCommandLineToken( 2, aLine ) );
+ fTop = StringToDouble( GetCommandLineToken( 3, aLine ) );
+ }
+ }
+ else if( aLine.CompareIgnoreCaseToAscii( "%%Title:", 8 ) == COMPARE_EQUAL )
+ aDocTitle = WhitespaceToSpace( aLine.Copy( 8 ) );
+ else if( aLine.CompareIgnoreCaseToAscii( "%%EndComments", 13 ) == COMPARE_EQUAL )
+ bEndComments = true;
+ }
+ else if( cChar == ' ' || cChar == '\t' || cChar == '\r' || cChar == '\n' )
+ bEndComments = true;
+ }
+ else
+ bEndComments = true;
+ }
+
+ static sal_uInt16 nEps = 0;
+ if( ! aDocTitle.Len() )
+ aDocTitle = ByteString::CreateFromInt32( (sal_Int32)(nEps++) );
+
+ if( fLeft != fRight && fTop != fBottom )
+ {
+ double fScaleX = (double)rBoundingBox.GetWidth()/(fRight-fLeft);
+ double fScaleY = -(double)rBoundingBox.GetHeight()/(fTop-fBottom);
+ Point aTranslatePoint( (int)(rBoundingBox.Left()-fLeft*fScaleX),
+ (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( 1 );
+ 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( ((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;
+}
diff --git a/vcl/unx/generic/printergfx/glyphset.cxx b/vcl/unx/generic/printergfx/glyphset.cxx
new file mode 100644
index 000000000000..9b0f5fb99c43
--- /dev/null
+++ b/vcl/unx/generic/printergfx/glyphset.cxx
@@ -0,0 +1,942 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "glyphset.hxx"
+#include "psputil.hxx"
+
+#include "sft.hxx"
+
+#include "printergfx.hxx"
+#include "fontsubset.hxx"
+#include "vcl/fontmanager.hxx"
+
+#include "osl/thread.h"
+
+#include "sal/alloca.h"
+
+#include "rtl/ustring.hxx"
+#include "rtl/strbuf.hxx"
+
+#include <set>
+#include <map>
+#include <algorithm>
+
+using namespace vcl;
+using namespace psp;
+using namespace rtl;
+
+GlyphSet::GlyphSet ()
+ : mnFontID (-1),
+ mbVertical (0),
+ mbUseFontEncoding (false)
+{}
+
+GlyphSet::GlyphSet (sal_Int32 nFontID, sal_Bool bVertical)
+ : mnFontID (nFontID),
+ mbVertical (bVertical)
+{
+ PrintFontManager &rMgr = PrintFontManager::get();
+ meBaseType = rMgr.getFontType (mnFontID);
+ maBaseName = OUStringToOString (rMgr.getPSName(mnFontID),
+ RTL_TEXTENCODING_ASCII_US);
+ mnBaseEncoding = rMgr.getFontEncoding(mnFontID);
+ mbUseFontEncoding = rMgr.getUseOnlyFontEncoding(mnFontID);
+}
+
+GlyphSet::~GlyphSet ()
+{
+ /* FIXME delete the glyphlist ??? */
+}
+
+sal_Int32
+GlyphSet::GetFontID ()
+{
+ return mnFontID;
+}
+
+fonttype::type
+GlyphSet::GetFontType ()
+{
+ return meBaseType;
+}
+
+sal_Bool
+GlyphSet::IsVertical ()
+{
+ return mbVertical;
+}
+
+sal_Bool
+GlyphSet::SetFont (sal_Int32 nFontID, sal_Bool bVertical)
+{
+ if (mnFontID != -1)
+ return sal_False;
+
+ mnFontID = nFontID;
+ mbVertical = bVertical;
+
+ PrintFontManager &rMgr = PrintFontManager::get();
+ meBaseType = rMgr.getFontType (mnFontID);
+ maBaseName = OUStringToOString (rMgr.getPSName(mnFontID),
+ RTL_TEXTENCODING_ASCII_US);
+ mnBaseEncoding = rMgr.getFontEncoding(mnFontID);
+ mbUseFontEncoding = rMgr.getUseOnlyFontEncoding(mnFontID);
+
+ return sal_True;
+}
+
+sal_Bool
+GlyphSet::GetCharID (
+ sal_Unicode nChar,
+ sal_uChar* nOutGlyphID,
+ sal_Int32* nOutGlyphSetID
+ )
+{
+ return LookupCharID (nChar, nOutGlyphID, nOutGlyphSetID)
+ || AddCharID (nChar, nOutGlyphID, nOutGlyphSetID);
+}
+
+sal_Bool
+GlyphSet::GetGlyphID (
+ sal_uInt32 nGlyph,
+ sal_Unicode nUnicode,
+ sal_uChar* nOutGlyphID,
+ sal_Int32* nOutGlyphSetID
+ )
+{
+ return LookupGlyphID (nGlyph, nOutGlyphID, nOutGlyphSetID)
+ || AddGlyphID (nGlyph, nUnicode, nOutGlyphID, nOutGlyphSetID);
+}
+
+sal_Bool
+GlyphSet::LookupCharID (
+ sal_Unicode nChar,
+ sal_uChar* nOutGlyphID,
+ sal_Int32* nOutGlyphSetID
+ )
+{
+ char_list_t::iterator aGlyphSet;
+ sal_Int32 nGlyphSetID;
+
+ // loop thru all the font subsets
+ for (aGlyphSet = maCharList.begin(), nGlyphSetID = 1;
+ aGlyphSet != maCharList.end();
+ ++aGlyphSet, nGlyphSetID++)
+ {
+ // check every subset if it contains the queried unicode char
+ char_map_t::const_iterator aGlyph = (*aGlyphSet).find (nChar);
+ if (aGlyph != (*aGlyphSet).end())
+ {
+ // success: found the unicode char, return the glyphid and the glyphsetid
+ *nOutGlyphSetID = nGlyphSetID;
+ *nOutGlyphID = (*aGlyph).second;
+ return sal_True;
+ }
+ }
+
+ *nOutGlyphSetID = -1;
+ *nOutGlyphID = 0;
+ return sal_False;
+}
+
+sal_Bool
+GlyphSet::LookupGlyphID (
+ sal_uInt32 nGlyph,
+ sal_uChar* nOutGlyphID,
+ sal_Int32* nOutGlyphSetID
+ )
+{
+ glyph_list_t::iterator aGlyphSet;
+ sal_Int32 nGlyphSetID;
+
+ // loop thru all the font subsets
+ for (aGlyphSet = maGlyphList.begin(), nGlyphSetID = 1;
+ aGlyphSet != maGlyphList.end();
+ ++aGlyphSet, nGlyphSetID++)
+ {
+ // check every subset if it contains the queried unicode char
+ glyph_map_t::const_iterator aGlyph = (*aGlyphSet).find (nGlyph);
+ if (aGlyph != (*aGlyphSet).end())
+ {
+ // success: found the glyph id, return the mapped glyphid and the glyphsetid
+ *nOutGlyphSetID = nGlyphSetID;
+ *nOutGlyphID = (*aGlyph).second;
+ return sal_True;
+ }
+ }
+
+ *nOutGlyphSetID = -1;
+ *nOutGlyphID = 0;
+ return sal_False;
+}
+
+sal_uChar
+GlyphSet::GetAnsiMapping (sal_Unicode nUnicodeChar)
+{
+ static rtl_UnicodeToTextConverter aConverter =
+ rtl_createUnicodeToTextConverter(RTL_TEXTENCODING_MS_1252);
+ static rtl_UnicodeToTextContext aContext =
+ rtl_createUnicodeToTextContext( aConverter );
+
+ sal_Char nAnsiChar;
+ sal_uInt32 nCvtInfo;
+ sal_Size nCvtChars;
+ const sal_uInt32 nCvtFlags = RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR
+ | RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR;
+
+ sal_Size nSize = rtl_convertUnicodeToText( aConverter, aContext,
+ &nUnicodeChar, 1, &nAnsiChar, 1,
+ nCvtFlags, &nCvtInfo, &nCvtChars );
+
+ return nSize == 1 ? (sal_uChar)nAnsiChar : (sal_uChar)0;
+}
+
+sal_uChar
+GlyphSet::GetSymbolMapping (sal_Unicode nUnicodeChar)
+{
+ if (0x0000 < nUnicodeChar && nUnicodeChar < 0x0100)
+ return (sal_uChar)nUnicodeChar;
+ if (0xf000 < nUnicodeChar && nUnicodeChar < 0xf100)
+ return (sal_uChar)nUnicodeChar;
+
+ return 0;
+}
+
+void
+GlyphSet::AddNotdef (char_map_t &rCharMap)
+{
+ if (rCharMap.size() == 0)
+ rCharMap[0] = 0;
+}
+
+void
+GlyphSet::AddNotdef (glyph_map_t &rGlyphMap)
+{
+ if (rGlyphMap.size() == 0)
+ rGlyphMap[0] = 0;
+}
+sal_Bool
+GlyphSet::AddCharID (
+ sal_Unicode nChar,
+ sal_uChar* nOutGlyphID,
+ sal_Int32* nOutGlyphSetID
+ )
+{
+ sal_uChar nMappedChar;
+
+ // XXX important: avoid to reencode type1 symbol fonts
+ if (mnBaseEncoding == RTL_TEXTENCODING_SYMBOL)
+ nMappedChar = GetSymbolMapping (nChar);
+ else
+ nMappedChar = GetAnsiMapping (nChar);
+
+ // create an empty glyphmap that is reserved for iso1252 encoded glyphs
+ // (or -- unencoded -- symbol glyphs) and a second map that takes any other
+ if (maCharList.empty())
+ {
+ char_map_t aMap, aMapp;
+
+ maCharList.push_back (aMap);
+ maCharList.push_back (aMapp);
+ }
+ // if the last map is full, create a new one
+ if ((!nMappedChar) && (maCharList.back().size() == 255))
+ {
+ char_map_t aMap;
+ maCharList.push_back (aMap);
+ }
+
+ // insert a new glyph in the font subset
+ if (nMappedChar)
+ {
+ // always put iso1252 chars into the first map, map them on itself
+ char_map_t& aGlyphSet = maCharList.front();
+ AddNotdef (aGlyphSet);
+
+ aGlyphSet [nChar] = nMappedChar;
+ *nOutGlyphSetID = 1;
+ *nOutGlyphID = nMappedChar;
+ }
+ else
+ {
+ // other chars are just appended to the list
+ char_map_t& aGlyphSet = maCharList.back();
+ AddNotdef (aGlyphSet);
+
+ int nSize = aGlyphSet.size();
+
+ aGlyphSet [nChar] = nSize;
+ *nOutGlyphSetID = maCharList.size();
+ *nOutGlyphID = aGlyphSet [nChar];
+ }
+
+ return sal_True;
+}
+
+sal_Bool
+GlyphSet::AddGlyphID (
+ sal_uInt32 nGlyph,
+ sal_Unicode nUnicode,
+ sal_uChar* nOutGlyphID,
+ sal_Int32* nOutGlyphSetID
+ )
+{
+ sal_uChar nMappedChar;
+
+ // XXX important: avoid to reencode type1 symbol fonts
+ if (mnBaseEncoding == RTL_TEXTENCODING_SYMBOL)
+ nMappedChar = GetSymbolMapping (nUnicode);
+ else
+ nMappedChar = GetAnsiMapping (nUnicode);
+
+ // create an empty glyphmap that is reserved for iso1252 encoded glyphs
+ // (or -- 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 ((!nMappedChar) && (maGlyphList.back().size() == 255))
+ {
+ glyph_map_t aMap;
+ maGlyphList.push_back (aMap);
+ }
+
+ // insert a new glyph in the font subset
+ if (nMappedChar)
+ {
+ // always put iso1252 chars into the first map, map them on itself
+ glyph_map_t& aGlyphSet = maGlyphList.front();
+ AddNotdef (aGlyphSet);
+
+ aGlyphSet [nGlyph] = nMappedChar;
+ *nOutGlyphSetID = 1;
+ *nOutGlyphID = nMappedChar;
+ }
+ else
+ {
+ // other chars are just appended to the list
+ glyph_map_t& aGlyphSet = maGlyphList.back();
+ AddNotdef (aGlyphSet);
+
+ int nSize = aGlyphSet.size();
+
+ aGlyphSet [nGlyph] = nSize;
+ *nOutGlyphSetID = maGlyphList.size();
+ *nOutGlyphID = aGlyphSet [nGlyph];
+ }
+
+ return sal_True;
+}
+
+OString
+GlyphSet::GetCharSetName (sal_Int32 nGlyphSetID)
+{
+ if (meBaseType == fonttype::TrueType)
+ {
+ OStringBuffer aSetName( maBaseName.getLength() + 32 );
+ aSetName.append( maBaseName );
+ aSetName.append( "FID" );
+ aSetName.append( mnFontID );
+ aSetName.append( mbVertical ? "VCSet" : "HCSet" );
+ aSetName.append( nGlyphSetID );
+ return aSetName.makeStringAndClear();
+ }
+ else
+ /* (meBaseType == fonttype::Type1 || meBaseType == fonttype::Builtin) */
+ {
+ return maBaseName;
+ }
+}
+
+OString
+GlyphSet::GetGlyphSetName (sal_Int32 nGlyphSetID)
+{
+ if (meBaseType == fonttype::TrueType)
+ {
+ OStringBuffer aSetName( maBaseName.getLength() + 32 );
+ aSetName.append( maBaseName );
+ aSetName.append( "FID" );
+ aSetName.append( mnFontID );
+ aSetName.append( mbVertical ? "VGSet" : "HGSet" );
+ aSetName.append( nGlyphSetID );
+ return aSetName.makeStringAndClear();
+ }
+ else
+ /* (meBaseType == fonttype::Type1 || meBaseType == fonttype::Builtin) */
+ {
+ return maBaseName;
+ }
+}
+
+sal_Int32
+GlyphSet::GetGlyphSetEncoding (sal_Int32 nGlyphSetID)
+{
+ if (meBaseType == fonttype::TrueType)
+ return RTL_TEXTENCODING_DONTKNOW;
+ else
+ {
+ /* (meBaseType == fonttype::Type1 || meBaseType == fonttype::Builtin) */
+ if (mnBaseEncoding == RTL_TEXTENCODING_SYMBOL)
+ return RTL_TEXTENCODING_SYMBOL;
+ else
+ return nGlyphSetID == 1 ? RTL_TEXTENCODING_MS_1252
+ : RTL_TEXTENCODING_USER_START + nGlyphSetID;
+ }
+}
+
+OString
+GlyphSet::GetGlyphSetEncodingName (rtl_TextEncoding nEnc, const OString &rFontName)
+{
+ if ( nEnc == RTL_TEXTENCODING_MS_1252
+ || nEnc == RTL_TEXTENCODING_ISO_8859_1)
+ {
+ return OString("ISO1252Encoding");
+ }
+ else
+ if (nEnc >= RTL_TEXTENCODING_USER_START && nEnc <= RTL_TEXTENCODING_USER_END)
+ {
+ return rFontName
+ + OString("Enc")
+ + OString::valueOf ((sal_Int32)(nEnc - RTL_TEXTENCODING_USER_START));
+ }
+ else
+ {
+ return OString();
+ }
+}
+
+OString
+GlyphSet::GetGlyphSetEncodingName (sal_Int32 nGlyphSetID)
+{
+ return GetGlyphSetEncodingName (GetGlyphSetEncoding(nGlyphSetID), maBaseName);
+}
+
+void
+GlyphSet::PSDefineReencodedFont (osl::File* pOutFile, sal_Int32 nGlyphSetID)
+{
+ // only for ps fonts
+ if ((meBaseType != fonttype::Builtin) && (meBaseType != fonttype::Type1))
+ return;
+
+ sal_Char pEncodingVector [256];
+ sal_Int32 nSize = 0;
+
+ nSize += psp::appendStr ("(", pEncodingVector + nSize);
+ nSize += psp::appendStr (GetReencodedFontName(nGlyphSetID),
+ pEncodingVector + nSize);
+ nSize += psp::appendStr (") cvn (", pEncodingVector + nSize);
+ nSize += psp::appendStr (maBaseName.getStr(),
+ pEncodingVector + nSize);
+ nSize += psp::appendStr (") cvn ", pEncodingVector + nSize);
+ nSize += psp::appendStr (GetGlyphSetEncodingName(nGlyphSetID),
+ pEncodingVector + nSize);
+ nSize += psp::appendStr (" psp_definefont\n",
+ pEncodingVector + nSize);
+
+ psp::WritePS (pOutFile, pEncodingVector);
+}
+
+OString
+GlyphSet::GetReencodedFontName (rtl_TextEncoding nEnc, const OString &rFontName)
+{
+ if ( nEnc == RTL_TEXTENCODING_MS_1252
+ || nEnc == RTL_TEXTENCODING_ISO_8859_1)
+ {
+ return rFontName
+ + OString("-iso1252");
+ }
+ else
+ if (nEnc >= RTL_TEXTENCODING_USER_START && nEnc <= RTL_TEXTENCODING_USER_END)
+ {
+ return rFontName
+ + OString("-enc")
+ + OString::valueOf ((sal_Int32)(nEnc - RTL_TEXTENCODING_USER_START));
+ }
+ else
+ {
+ return OString();
+ }
+}
+
+OString
+GlyphSet::GetReencodedFontName (sal_Int32 nGlyphSetID)
+{
+ return GetReencodedFontName (GetGlyphSetEncoding(nGlyphSetID), maBaseName);
+}
+
+void GlyphSet::DrawGlyphs(
+ PrinterGfx& rGfx,
+ const Point& rPoint,
+ const sal_uInt32* pGlyphIds,
+ const sal_Unicode* pUnicodes,
+ sal_Int16 nLen,
+ const sal_Int32* pDeltaArray )
+{
+ sal_uChar *pGlyphID = (sal_uChar*)alloca (nLen * sizeof(sal_uChar));
+ sal_Int32 *pGlyphSetID = (sal_Int32*)alloca (nLen * sizeof(sal_Int32));
+ std::set< sal_Int32 > aGlyphSet;
+
+ // convert unicode to font glyph id and font subset
+ for (int nChar = 0; nChar < nLen; nChar++)
+ {
+ GetGlyphID (pGlyphIds[nChar], pUnicodes[nChar], pGlyphID + nChar, pGlyphSetID + nChar);
+ aGlyphSet.insert (pGlyphSetID[nChar]);
+ }
+
+ // loop over all glyph sets to detect substrings that can be xshown together
+ // without changing the postscript font
+ sal_Int32 *pDeltaSubset = (sal_Int32*)alloca (nLen * sizeof(sal_Int32));
+ sal_uChar *pGlyphSubset = (sal_uChar*)alloca (nLen * sizeof(sal_uChar));
+
+ std::set< sal_Int32 >::iterator aSet;
+ for (aSet = aGlyphSet.begin(); aSet != aGlyphSet.end(); ++aSet)
+ {
+ Point aPoint = rPoint;
+ sal_Int32 nOffset = 0;
+ sal_Int32 nGlyphs = 0;
+ sal_Int32 nChar;
+
+ // get offset to first glyph
+ for (nChar = 0; (nChar < nLen) && (pGlyphSetID[nChar] != *aSet); nChar++)
+ {
+ nOffset = pDeltaArray [nChar];
+ }
+
+ // loop over all chars to extract those that share the current glyph set
+ for (nChar = 0; nChar < nLen; nChar++)
+ {
+ if (pGlyphSetID[nChar] == *aSet)
+ {
+ pGlyphSubset [nGlyphs] = pGlyphID [nChar];
+ // the offset to the next glyph is determined by the glyph in
+ // front of the next glyph with the same glyphset id
+ // most often, this will be the current glyph
+ while ((nChar + 1) < nLen)
+ {
+ if (pGlyphSetID[nChar + 1] == *aSet)
+ break;
+ else
+ nChar += 1;
+ }
+ pDeltaSubset [nGlyphs] = pDeltaArray[nChar] - nOffset;
+
+ nGlyphs += 1;
+ }
+ }
+
+ // show the text using the PrinterGfx text api
+ aPoint.Move (nOffset, 0);
+
+ OString aGlyphSetName(GetGlyphSetName(*aSet));
+ rGfx.PSSetFont (aGlyphSetName, GetGlyphSetEncoding(*aSet));
+ rGfx.PSMoveTo (aPoint);
+ rGfx.PSShowText (pGlyphSubset, nGlyphs, nGlyphs, nGlyphs > 1 ? pDeltaSubset : NULL);
+ }
+}
+
+void
+GlyphSet::DrawText (PrinterGfx &rGfx, const Point& rPoint,
+ const sal_Unicode* pStr, sal_Int16 nLen, const sal_Int32* pDeltaArray)
+{
+ // dispatch to the impl method
+ if (pDeltaArray == NULL)
+ ImplDrawText (rGfx, rPoint, pStr, nLen);
+ else
+ ImplDrawText (rGfx, rPoint, pStr, nLen, pDeltaArray);
+}
+
+void
+GlyphSet::ImplDrawText (PrinterGfx &rGfx, const Point& rPoint,
+ const sal_Unicode* pStr, sal_Int16 nLen)
+{
+ rGfx.PSMoveTo (rPoint);
+
+ if( mbUseFontEncoding )
+ {
+ OString aPSName( OUStringToOString( rGfx.GetFontMgr().getPSName( mnFontID ), RTL_TEXTENCODING_ISO_8859_1 ) );
+ OString aBytes( OUStringToOString( OUString( pStr, nLen ), mnBaseEncoding ) );
+ rGfx.PSSetFont( aPSName, mnBaseEncoding );
+ rGfx.PSShowText( (const unsigned char*)aBytes.getStr(), nLen, aBytes.getLength() );
+ return;
+ }
+
+ int nChar;
+ sal_uChar *pGlyphID = (sal_uChar*)alloca (nLen * sizeof(sal_uChar));
+ sal_Int32 *pGlyphSetID = (sal_Int32*)alloca (nLen * sizeof(sal_Int32));
+
+ // convert unicode to glyph id and char set (font subset)
+ for (nChar = 0; nChar < nLen; nChar++)
+ GetCharID (pStr[nChar], pGlyphID + nChar, pGlyphSetID + nChar);
+
+ // loop over the string to draw subsequent pieces of chars
+ // with the same postscript font
+ for (nChar = 0; nChar < nLen; /* atend */)
+ {
+ sal_Int32 nGlyphSetID = pGlyphSetID [nChar];
+ sal_Int32 nGlyphs = 1;
+ for (int nNextChar = nChar + 1; nNextChar < nLen; nNextChar++)
+ {
+ if (pGlyphSetID[nNextChar] == nGlyphSetID)
+ nGlyphs++;
+ else
+ break;
+ }
+
+ // show the text using the PrinterGfx text api
+ OString aGlyphSetName(GetCharSetName(nGlyphSetID));
+ rGfx.PSSetFont (aGlyphSetName, GetGlyphSetEncoding(nGlyphSetID));
+ rGfx.PSShowText (pGlyphID + nChar, nGlyphs, nGlyphs);
+
+ nChar += nGlyphs;
+ }
+}
+
+void
+GlyphSet::ImplDrawText (PrinterGfx &rGfx, const Point& rPoint,
+ const sal_Unicode* pStr, sal_Int16 nLen, const sal_Int32* pDeltaArray)
+{
+ if( mbUseFontEncoding )
+ {
+ OString aPSName( OUStringToOString( rGfx.GetFontMgr().getPSName( mnFontID ), RTL_TEXTENCODING_ISO_8859_1 ) );
+ OString aBytes( OUStringToOString( OUString( pStr, nLen ), mnBaseEncoding ) );
+ rGfx.PSMoveTo( rPoint );
+ rGfx.PSSetFont( aPSName, mnBaseEncoding );
+ rGfx.PSShowText( (const unsigned char*)aBytes.getStr(), nLen, aBytes.getLength(), pDeltaArray );
+ return;
+ }
+
+ sal_uChar *pGlyphID = (sal_uChar*)alloca (nLen * sizeof(sal_uChar));
+ sal_Int32 *pGlyphSetID = (sal_Int32*)alloca (nLen * sizeof(sal_Int32));
+ std::set< sal_Int32 > aGlyphSet;
+
+ // convert unicode to font glyph id and font subset
+ for (int nChar = 0; nChar < nLen; nChar++)
+ {
+ GetCharID (pStr[nChar], pGlyphID + nChar, pGlyphSetID + nChar);
+ aGlyphSet.insert (pGlyphSetID[nChar]);
+ }
+
+ // loop over all glyph sets to detect substrings that can be xshown together
+ // without changing the postscript font
+ sal_Int32 *pDeltaSubset = (sal_Int32*)alloca (nLen * sizeof(sal_Int32));
+ sal_uChar *pGlyphSubset = (sal_uChar*)alloca (nLen * sizeof(sal_uChar));
+
+ std::set< sal_Int32 >::iterator aSet;
+ for (aSet = aGlyphSet.begin(); aSet != aGlyphSet.end(); ++aSet)
+ {
+ Point aPoint = rPoint;
+ sal_Int32 nOffset = 0;
+ sal_Int32 nGlyphs = 0;
+ sal_Int32 nChar;
+
+ // get offset to first glyph
+ for (nChar = 0; (nChar < nLen) && (pGlyphSetID[nChar] != *aSet); nChar++)
+ {
+ nOffset = pDeltaArray [nChar];
+ }
+
+ // loop over all chars to extract those that share the current glyph set
+ for (nChar = 0; nChar < nLen; nChar++)
+ {
+ if (pGlyphSetID[nChar] == *aSet)
+ {
+ pGlyphSubset [nGlyphs] = pGlyphID [nChar];
+ // the offset to the next glyph is determined by the glyph in
+ // front of the next glyph with the same glyphset id
+ // most often, this will be the current glyph
+ while ((nChar + 1) < nLen)
+ {
+ if (pGlyphSetID[nChar + 1] == *aSet)
+ break;
+ else
+ nChar += 1;
+ }
+ pDeltaSubset [nGlyphs] = pDeltaArray[nChar] - nOffset;
+
+ nGlyphs += 1;
+ }
+ }
+
+ // show the text using the PrinterGfx text api
+ aPoint.Move (nOffset, 0);
+
+ OString aGlyphSetName(GetCharSetName(*aSet));
+ rGfx.PSSetFont (aGlyphSetName, GetGlyphSetEncoding(*aSet));
+ rGfx.PSMoveTo (aPoint);
+ rGfx.PSShowText (pGlyphSubset, nGlyphs, nGlyphs, nGlyphs > 1 ? pDeltaSubset : NULL);
+ }
+}
+
+sal_Bool
+GlyphSet::PSUploadEncoding(osl::File* pOutFile, PrinterGfx &rGfx)
+{
+ // only for ps fonts
+ if ((meBaseType != fonttype::Builtin) && (meBaseType != fonttype::Type1))
+ return sal_False;
+ if (mnBaseEncoding == RTL_TEXTENCODING_SYMBOL)
+ return sal_False;
+
+ PrintFontManager &rMgr = rGfx.GetFontMgr();
+
+ // loop thru all the font subsets
+ sal_Int32 nGlyphSetID = 0;
+ char_list_t::iterator aGlyphSet;
+ for (aGlyphSet = maCharList.begin(); aGlyphSet != maCharList.end(); aGlyphSet++)
+ {
+ ++nGlyphSetID;
+
+ if (nGlyphSetID == 1) // latin1 page uses global reencoding table
+ {
+ PSDefineReencodedFont (pOutFile, nGlyphSetID);
+ continue;
+ }
+ if ((*aGlyphSet).size() == 0) // empty set, doesn't need reencoding
+ {
+ continue;
+ }
+
+ // create reencoding table
+
+ sal_Char pEncodingVector [256];
+ sal_Int32 nSize = 0;
+
+ nSize += psp::appendStr ("/",
+ pEncodingVector + nSize);
+ nSize += psp::appendStr (GetGlyphSetEncodingName(nGlyphSetID),
+ pEncodingVector + nSize);
+ nSize += psp::appendStr (" [ ",
+ pEncodingVector + nSize);
+
+ // need a list of glyphs, sorted by glyphid
+ typedef std::map< sal_uInt8, sal_Unicode > ps_mapping_t;
+ typedef ps_mapping_t::value_type ps_value_t;
+ ps_mapping_t aSortedGlyphSet;
+
+ char_map_t::const_iterator aUnsortedGlyph;
+ for (aUnsortedGlyph = (*aGlyphSet).begin();
+ aUnsortedGlyph != (*aGlyphSet).end();
+ ++aUnsortedGlyph)
+ {
+ aSortedGlyphSet.insert(ps_value_t((*aUnsortedGlyph).second,
+ (*aUnsortedGlyph).first));
+ }
+
+ ps_mapping_t::const_iterator aSortedGlyph;
+ // loop thru all the glyphs in the subset
+ for (aSortedGlyph = (aSortedGlyphSet).begin();
+ aSortedGlyph != (aSortedGlyphSet).end();
+ ++aSortedGlyph)
+ {
+ nSize += psp::appendStr ("/",
+ pEncodingVector + nSize);
+
+ std::list< OString > aName( rMgr.getAdobeNameFromUnicode((*aSortedGlyph).second) );
+
+ if( aName.begin() != aName.end() )
+ nSize += psp::appendStr ( aName.front(), pEncodingVector + nSize);
+ else
+ nSize += psp::appendStr (".notdef", pEncodingVector + nSize );
+ nSize += psp::appendStr (" ", pEncodingVector + nSize);
+ // flush line
+ if (nSize >= 70)
+ {
+ nSize += psp::appendStr ("\n", pEncodingVector + nSize);
+ psp::WritePS (pOutFile, pEncodingVector);
+ nSize = 0;
+ }
+ }
+
+ nSize += psp::appendStr ("] def\n", pEncodingVector + nSize);
+ psp::WritePS (pOutFile, pEncodingVector);
+
+ PSDefineReencodedFont (pOutFile, nGlyphSetID);
+ }
+
+ return sal_True;
+}
+
+struct EncEntry
+{
+ sal_uChar aEnc;
+ long aGID;
+
+ EncEntry() : aEnc( 0 ), aGID( 0 ) {}
+
+ bool operator<( const EncEntry& rRight ) const
+ { return aEnc < rRight.aEnc; }
+};
+
+static void CreatePSUploadableFont( TrueTypeFont* pSrcFont, FILE* pTmpFile,
+ const char* pGlyphSetName, int nGlyphCount,
+ /*const*/ sal_uInt16* pRequestedGlyphs, /*const*/ sal_uChar* pEncoding,
+ bool bAllowType42, bool /*bAllowCID*/ )
+{
+ // match the font-subset to the printer capabilities
+ // TODO: allow CFF for capable printers
+ int nTargetMask = FontSubsetInfo::TYPE1_PFA | FontSubsetInfo::TYPE3_FONT;
+ if( bAllowType42 )
+ nTargetMask |= FontSubsetInfo::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< sal_uChar > aEncoding( nGlyphCount );
+ std::vector< long > 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[0], &aEncoding[0], nGlyphCount, NULL );
+}
+
+sal_Bool
+GlyphSet::PSUploadFont (osl::File& rOutFile, PrinterGfx &rGfx, bool bAllowType42, std::list< OString >& rSuppliedFonts )
+{
+ // only for truetype fonts
+ if (meBaseType != fonttype::TrueType)
+ return sal_False;
+
+ TrueTypeFont *pTTFont;
+ OString aTTFileName (rGfx.GetFontMgr().getFontFileSysPath(mnFontID));
+ int nFace = rGfx.GetFontMgr().getFontFaceNumber(mnFontID);
+ sal_Int32 nSuccess = OpenTTFontFile(aTTFileName.getStr(), nFace < 0 ? 0 : nFace, &pTTFont);
+ if (nSuccess != SF_OK)
+ return sal_False;
+ FILE* pTmpFile = tmpfile();
+ if (pTmpFile == NULL)
+ return sal_False;
+
+ // array of unicode source characters
+ sal_Unicode pUChars[256];
+
+ // encoding vector maps character encoding to the ordinal number
+ // of the glyph in the output file
+ sal_uChar pEncoding[256];
+ sal_uInt16 pTTGlyphMapping[256];
+ const bool bAllowCID = false; // TODO: nPSLanguageLevel>=3
+
+ // loop thru all the font subsets
+ sal_Int32 nCharSetID;
+ char_list_t::iterator aCharSet;
+ for (aCharSet = maCharList.begin(), nCharSetID = 1;
+ aCharSet != maCharList.end();
+ ++aCharSet, nCharSetID++)
+ {
+ if ((*aCharSet).size() == 0)
+ continue;
+
+ // loop thru all the chars in the subset
+ char_map_t::const_iterator aChar;
+ sal_Int32 n = 0;
+ for (aChar = (*aCharSet).begin(); aChar != (*aCharSet).end(); aChar++)
+ {
+ pUChars [n] = (*aChar).first;
+ pEncoding [n] = (*aChar).second;
+ n++;
+ }
+ // create a mapping from the unicode chars to the char encoding in
+ // source TrueType font
+ MapString (pTTFont, pUChars, (*aCharSet).size(), pTTGlyphMapping, mbVertical);
+
+ // create the current subset
+ OString aCharSetName = GetCharSetName(nCharSetID);
+ fprintf( pTmpFile, "%%%%BeginResource: font %s\n", aCharSetName.getStr() );
+ CreatePSUploadableFont( pTTFont, pTmpFile, aCharSetName.getStr(), (*aCharSet).size(),
+ pTTGlyphMapping, pEncoding, bAllowType42, bAllowCID );
+ fprintf( pTmpFile, "%%%%EndResource\n" );
+ rSuppliedFonts.push_back( aCharSetName );
+ }
+
+ // loop thru all the font glyph subsets
+ sal_Int32 nGlyphSetID;
+ glyph_list_t::iterator aGlyphSet;
+ for (aGlyphSet = maGlyphList.begin(), nGlyphSetID = 1;
+ aGlyphSet != maGlyphList.end();
+ ++aGlyphSet, nGlyphSetID++)
+ {
+ if ((*aGlyphSet).size() == 0)
+ continue;
+
+ // loop thru all the glyphs in the subset
+ glyph_map_t::const_iterator aGlyph;
+ sal_Int32 n = 0;
+ for (aGlyph = (*aGlyphSet).begin(); aGlyph != (*aGlyphSet).end(); aGlyph++)
+ {
+ pTTGlyphMapping [n] = (*aGlyph).first;
+ pEncoding [n] = (*aGlyph).second;
+ n++;
+ }
+
+ // create the current subset
+ OString aGlyphSetName = GetGlyphSetName(nGlyphSetID);
+ fprintf( pTmpFile, "%%%%BeginResource: font %s\n", aGlyphSetName.getStr() );
+ CreatePSUploadableFont( pTTFont, pTmpFile, aGlyphSetName.getStr(), (*aGlyphSet).size(),
+ pTTGlyphMapping, pEncoding, bAllowType42, bAllowCID );
+ fprintf( pTmpFile, "%%%%EndResource\n" );
+ rSuppliedFonts.push_back( aGlyphSetName );
+ }
+
+ // copy the file into the page header
+ rewind(pTmpFile);
+ fflush(pTmpFile);
+
+ sal_uChar pBuffer[0x2000];
+ sal_uInt64 nIn;
+ sal_uInt64 nOut;
+ do
+ {
+ nIn = fread(pBuffer, 1, sizeof(pBuffer), pTmpFile);
+ rOutFile.write (pBuffer, nIn, nOut);
+ }
+ while ((nIn == nOut) && !feof(pTmpFile));
+
+ // cleanup
+ CloseTTFont (pTTFont);
+ fclose (pTmpFile);
+
+ return sal_True;
+}
diff --git a/vcl/unx/generic/printergfx/glyphset.hxx b/vcl/unx/generic/printergfx/glyphset.hxx
new file mode 100644
index 000000000000..320e8e071955
--- /dev/null
+++ b/vcl/unx/generic/printergfx/glyphset.hxx
@@ -0,0 +1,135 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _PSPRINT_GLYPHSET_HXX_
+#define _PSPRINT_GLYPHSET_HXX_
+
+#include "vcl/fontmanager.hxx"
+
+#include "osl/file.hxx"
+
+#include "rtl/string.hxx"
+
+#include "tools/gen.hxx"
+
+#include <list>
+#include <hash_map>
+
+namespace psp {
+
+class PrinterGfx;
+class PrintFontManager;
+
+class GlyphSet
+{
+private:
+
+ sal_Int32 mnFontID;
+ sal_Bool mbVertical;
+ rtl::OString maBaseName;
+ fonttype::type meBaseType;
+ rtl_TextEncoding mnBaseEncoding;
+ bool mbUseFontEncoding;
+
+ typedef std::hash_map< sal_Unicode, sal_uInt8 > char_map_t;
+ typedef std::list< char_map_t > char_list_t;
+ typedef std::hash_map< sal_uInt32, sal_uInt8 > glyph_map_t;
+ typedef std::list< glyph_map_t > glyph_list_t;
+
+ char_list_t maCharList;
+ glyph_list_t maGlyphList;
+
+ rtl::OString GetGlyphSetName (sal_Int32 nGlyphSetID);
+ rtl::OString GetCharSetName (sal_Int32 nGlyphSetID);
+ sal_Int32 GetGlyphSetEncoding (sal_Int32 nGlyphSetID);
+ rtl::OString GetGlyphSetEncodingName (sal_Int32 nGlyphSetID);
+
+ rtl::OString GetReencodedFontName (sal_Int32 nGlyphSetID);
+ void PSDefineReencodedFont (osl::File* pOutFile,
+ sal_Int32 nGlyphSetID);
+
+ sal_Bool GetCharID (sal_Unicode nChar,
+ sal_uChar* nOutGlyphID, sal_Int32* nOutGlyphSetID);
+ sal_Bool LookupCharID (sal_Unicode nChar,
+ sal_uChar* nOutGlyphID, sal_Int32* nOutGlyphSetID);
+ sal_Bool AddCharID (sal_Unicode nChar,
+ sal_uChar* nOutGlyphID,
+ sal_Int32* nOutGlyphSetID);
+ sal_Bool GetGlyphID (sal_uInt32 nGlyph, sal_Unicode nUnicode,
+ sal_uChar* nOutGlyphID, sal_Int32* nOutGlyphSetID);
+ sal_Bool LookupGlyphID (sal_uInt32 nGlyph,
+ sal_uChar* nOutGlyphID, sal_Int32* nOutGlyphSetID);
+ sal_Bool AddGlyphID (sal_uInt32 nGlyph, sal_Unicode nUnicode,
+ sal_uChar* nOutGlyphID,
+ sal_Int32* nOutGlyphSetID);
+ void AddNotdef (char_map_t &rCharMap);
+ void AddNotdef (glyph_map_t &rGlyphMap);
+ sal_uChar GetAnsiMapping (sal_Unicode nUnicodeChar);
+ sal_uChar GetSymbolMapping (sal_Unicode nUnicodeChar);
+
+ void ImplDrawText (PrinterGfx &rGfx, const Point& rPoint,
+ const sal_Unicode* pStr, sal_Int16 nLen);
+ void ImplDrawText (PrinterGfx &rGfx, const Point& rPoint,
+ const sal_Unicode* pStr, sal_Int16 nLen,
+ const sal_Int32* pDeltaArray);
+
+public:
+
+ GlyphSet ();
+ GlyphSet (sal_Int32 nFontID, sal_Bool bVertical);
+ ~GlyphSet ();
+
+ sal_Int32 GetFontID ();
+ fonttype::type GetFontType ();
+ static rtl::OString
+ GetReencodedFontName (rtl_TextEncoding nEnc,
+ const rtl::OString &rFontName);
+ static rtl::OString
+ GetGlyphSetEncodingName (rtl_TextEncoding nEnc,
+ const rtl::OString &rFontName);
+ sal_Bool IsVertical ();
+
+ sal_Bool SetFont (sal_Int32 nFontID, sal_Bool bVertical);
+
+ void DrawText (PrinterGfx &rGfx, const Point& rPoint,
+ const sal_Unicode* pStr, sal_Int16 nLen,
+ const sal_Int32* pDeltaArray = NULL);
+ void DrawGlyphs (PrinterGfx& rGfx,
+ const Point& rPoint,
+ const sal_uInt32* pGlyphIds,
+ const sal_Unicode* pUnicodes,
+ sal_Int16 nLen,
+ const sal_Int32* pDeltaArray );
+ sal_Bool PSUploadEncoding(osl::File* pOutFile, PrinterGfx &rGfx);
+ sal_Bool PSUploadFont (osl::File& rOutFile, PrinterGfx &rGfx, bool bAsType42, std::list< rtl::OString >& rSuppliedFonts );
+};
+
+
+} /* namespace psp */
+
+#endif
+
diff --git a/vcl/unx/generic/printergfx/printerjob.cxx b/vcl/unx/generic/printergfx/printerjob.cxx
new file mode 100644
index 000000000000..351d1af9b41d
--- /dev/null
+++ b/vcl/unx/generic/printergfx/printerjob.cxx
@@ -0,0 +1,1204 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <pwd.h>
+
+#include "psputil.hxx"
+#include "glyphset.hxx"
+
+#include "printerjob.hxx"
+#include "printergfx.hxx"
+#include "vcl/ppdparser.hxx"
+#include "vcl/strhelper.hxx"
+#include "vcl/printerinfomanager.hxx"
+
+#include "rtl/ustring.hxx"
+#include "rtl/strbuf.hxx"
+#include "rtl/ustrbuf.hxx"
+
+#include "osl/thread.h"
+#include "sal/alloca.h"
+
+#include <algorithm>
+#include <vector>
+
+using namespace psp;
+using namespace rtl;
+
+// forward declaration
+
+#define nBLOCKSIZE 0x2000
+
+namespace psp
+{
+
+sal_Bool
+AppendPS (FILE* pDst, osl::File* pSrc, sal_uChar* pBuffer,
+ sal_uInt32 nBlockSize = nBLOCKSIZE)
+{
+ if ((pDst == NULL) || (pSrc == NULL))
+ return sal_False;
+
+ if (nBlockSize == 0)
+ nBlockSize = nBLOCKSIZE;
+ if (pBuffer == NULL)
+ pBuffer = (sal_uChar*)alloca (nBlockSize);
+
+ pSrc->setPos (osl_Pos_Absolut, 0);
+
+ 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 sal_True;
+}
+
+} // namespace psp
+
+/*
+ * private convenience routines for file handling
+ */
+
+osl::File*
+PrinterJob::CreateSpoolFile (const rtl::OUString& rName, const rtl::OUString& rExtension)
+{
+ osl::File::RC nError = osl::File::E_None;
+ osl::File* pFile = NULL;
+
+ rtl::OUString aFile = rName + rExtension;
+ rtl::OUString aFileURL;
+ nError = osl::File::getFileURLFromSystemPath( aFile, aFileURL );
+ if (nError != osl::File::E_None)
+ return NULL;
+ aFileURL = maSpoolDirName + rtl::OUString::createFromAscii ("/") + aFileURL;
+
+ pFile = new osl::File (aFileURL);
+ nError = pFile->open (OpenFlag_Read | OpenFlag_Write | OpenFlag_Create);
+ if (nError != osl::File::E_None)
+ {
+ delete pFile;
+ return NULL;
+ }
+
+ pFile->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();
+ sal_Bool bColor = IsColorPrinter ();
+
+ return nLevel > 1 && bColor ? 24 : 8;
+}
+
+sal_uInt16
+PrinterJob::GetPostscriptLevel (const JobData *pJobData) const
+{
+ sal_uInt16 nPSLevel = 2;
+
+ if( pJobData == NULL )
+ pJobData = &m_aLastJobData;
+
+ if( pJobData->m_nPSLevel )
+ nPSLevel = pJobData->m_nPSLevel;
+ else
+ if( pJobData->m_pParser )
+ nPSLevel = pJobData->m_pParser->getLanguageLevel();
+
+ return nPSLevel;
+}
+
+sal_Bool
+PrinterJob::IsColorPrinter () const
+{
+ sal_Bool bColor = sal_False;
+
+ if( m_aLastJobData.m_nColorDevice )
+ bColor = m_aLastJobData.m_nColorDevice == -1 ? sal_False : sal_True;
+ else if( m_aLastJobData.m_pParser )
+ bColor = m_aLastJobData.m_pParser->isColorDevice() ? sal_True : sal_False;
+
+ return bColor;
+}
+
+osl::File*
+PrinterJob::GetDocumentHeader ()
+{
+ return mpJobHeader;
+}
+
+osl::File*
+PrinterJob::GetDocumentTrailer ()
+{
+ return mpJobTrailer;
+}
+
+osl::File*
+PrinterJob::GetCurrentPageHeader ()
+{
+ return maHeaderList.back();
+}
+
+osl::File*
+PrinterJob::GetCurrentPageBody ()
+{
+ return maPageList.back();
+}
+
+/*
+ * public methods of PrinterJob: the actual job / spool handling
+ */
+
+PrinterJob::PrinterJob () :
+ mpJobHeader( NULL ),
+ mpJobTrailer( NULL ),
+ m_bQuickJob( false )
+{
+}
+
+namespace psp
+{
+
+/* check whether the given name points to a directory which is
+ usable for the user */
+sal_Bool
+existsTmpDir (const char* pName)
+{
+ struct stat aFileStatus;
+
+ if (pName == NULL)
+ return sal_False;
+ if (stat(pName, &aFileStatus) != 0)
+ return sal_False;
+ if (! S_ISDIR(aFileStatus.st_mode))
+ return sal_False;
+
+ return access(pName, W_OK | R_OK) == 0 ? sal_True : sal_False;
+}
+
+/* return the username in the given buffer */
+sal_Bool
+getUserName (char* pName, int nSize)
+{
+ struct passwd *pPWEntry;
+ struct passwd aPWEntry;
+ sal_Char pPWBuffer[256];
+
+ sal_Bool bSuccess = sal_False;
+
+#ifdef FREEBSD
+ pPWEntry = getpwuid( getuid());
+#else
+ if (getpwuid_r(getuid(), &aPWEntry, pPWBuffer, sizeof(pPWBuffer), &pPWEntry) != 0)
+ pPWEntry = NULL;
+#endif
+
+ if (pPWEntry != NULL && pPWEntry->pw_name != NULL)
+ {
+ sal_Int32 nLen = strlen(pPWEntry->pw_name);
+ if (nLen > 0 && nLen < nSize)
+ {
+ memcpy (pName, pPWEntry->pw_name, nLen);
+ pName[nLen] = '\0';
+
+ bSuccess = sal_True;
+ }
+ }
+
+ // wipe the passwd off the stack
+ memset (pPWBuffer, 0, sizeof(pPWBuffer));
+
+ return bSuccess;
+}
+
+/* remove all our temporary files, uses external program "rm", since
+ osl functionality is inadequate */
+void
+removeSpoolDir (const rtl::OUString& rSpoolDir)
+{
+ rtl::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_ENSURE( 0, "psprint: couldn't remove spool directory" );
+ return;
+ }
+ rtl::OString aSysPathByte =
+ rtl::OUStringToOString (aSysPath, osl_getThreadTextEncoding());
+ sal_Char pSystem [128];
+ sal_Int32 nChar = 0;
+
+ nChar = psp::appendStr ("rm -rf ", pSystem);
+ nChar += psp::appendStr (aSysPathByte.getStr(), pSystem + nChar);
+
+ if (system (pSystem) == -1)
+ OSL_ENSURE( 0, "psprint: couldn't remove spool directory" );
+}
+
+/* creates a spool directory with a "pidgin random" value based on
+ current system time */
+rtl::OUString
+createSpoolDir ()
+{
+ TimeValue aCur;
+ osl_getSystemTime( &aCur );
+ sal_Int32 nRand = aCur.Seconds ^ (aCur.Nanosec/1000);
+
+ rtl::OUString aTmpDir;
+ osl_getTempDirURL( &aTmpDir.pData );
+
+ do
+ {
+ rtl::OUStringBuffer aDir( aTmpDir.getLength() + 16 );
+ aDir.append( aTmpDir );
+ aDir.appendAscii( "/psp" );
+ aDir.append(nRand);
+ rtl::OUString aResult = aDir.makeStringAndClear();
+ if( osl::Directory::create( aResult ) == osl::FileBase::E_None )
+ {
+ osl::File::setAttributes( aResult,
+ osl_File_Attribute_OwnWrite
+ | osl_File_Attribute_OwnRead
+ | osl_File_Attribute_OwnExe );
+ return aResult;
+ }
+ nRand++;
+ } while( nRand );
+ return rtl::OUString();
+}
+
+} // namespace psp
+
+PrinterJob::~PrinterJob ()
+{
+ std::list< osl::File* >::iterator pPage;
+ for (pPage = maPageList.begin(); pPage != maPageList.end(); pPage++)
+ {
+ //(*pPage)->remove();
+ delete *pPage;
+ }
+ for (pPage = maHeaderList.begin(); pPage != maHeaderList.end(); pPage++)
+ {
+ //(*pPage)->remove();
+ delete *pPage;
+ }
+ // mpJobHeader->remove();
+ delete mpJobHeader;
+ // mpJobTrailer->remove();
+ delete mpJobTrailer;
+
+ // XXX should really call osl::remove routines
+ if( maSpoolDirName.getLength() )
+ removeSpoolDir (maSpoolDirName);
+
+ // osl::Directory::remove (maSpoolDirName);
+}
+
+namespace psp
+{
+
+// get locale invariant, 7bit clean current local time string
+sal_Char*
+getLocalTime(sal_Char* pBuffer)
+{
+ time_t nTime = time (NULL);
+ struct tm aTime;
+ struct tm *pLocalTime = localtime_r (&nTime, &aTime);
+
+ return asctime_r(pLocalTime, pBuffer);
+}
+
+}
+
+static bool isAscii( const rtl::OUString& rStr )
+{
+ const sal_Unicode* pStr = rStr;
+ sal_Int32 nLen = rStr.getLength();
+ for( sal_Int32 i = 0; i < nLen; i++ )
+ if( pStr[i] > 127 )
+ return false;
+ return true;
+}
+
+sal_Bool
+PrinterJob::StartJob (
+ const rtl::OUString& rFileName,
+ int nMode,
+ const rtl::OUString& rJobName,
+ const rtl::OUString& 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;
+
+ rtl::OUString aExt = rtl::OUString::createFromAscii (".ps");
+ mpJobHeader = CreateSpoolFile (rtl::OUString::createFromAscii("psp_head"), aExt);
+ mpJobTrailer = CreateSpoolFile (rtl::OUString::createFromAscii("psp_tail"), aExt);
+ if( ! (mpJobHeader && mpJobTrailer) ) // existing files are removed in destructor
+ return sal_False;
+
+ // write document header according to Document Structuring Conventions (DSC)
+ WritePS (mpJobHeader,
+ "%!PS-Adobe-3.0\n"
+ "%%BoundingBox: (atend)\n" );
+
+ rtl::OUString aFilterWS;
+
+ // Creator (this application)
+ aFilterWS = WhitespaceToSpace( rAppName, sal_False );
+ WritePS (mpJobHeader, "%%Creator: (");
+ WritePS (mpJobHeader, aFilterWS);
+ WritePS (mpJobHeader, ")\n");
+
+ // For (user name)
+ sal_Char pUserName[64];
+ if (getUserName(pUserName, sizeof(pUserName)))
+ {
+ WritePS (mpJobHeader, "%%For: (");
+ WritePS (mpJobHeader, pUserName);
+ WritePS (mpJobHeader, ")\n");
+ }
+
+ // Creation Date (locale independent local time)
+ sal_Char pCreationDate [256];
+ WritePS (mpJobHeader, "%%CreationDate: (");
+ getLocalTime(pCreationDate);
+ for( unsigned int i = 0; i < sizeof(pCreationDate)/sizeof(pCreationDate[0]); i++ )
+ {
+ if( pCreationDate[i] == '\n' )
+ {
+ pCreationDate[i] = 0;
+ break;
+ }
+ }
+ WritePS (mpJobHeader, pCreationDate );
+ WritePS (mpJobHeader, ")\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, sal_False );
+ rtl::OUString aTitle( aFilterWS );
+ if( ! isAscii( aTitle ) )
+ {
+ sal_Int32 nIndex = 0;
+ while( nIndex != -1 )
+ aTitle = rFileName.getToken( 0, '/', nIndex );
+ aTitle = WhitespaceToSpace( aTitle, sal_False );
+ if( ! isAscii( aTitle ) )
+ aTitle = rtl::OUString();
+ }
+
+ maJobTitle = aFilterWS;
+ if( aTitle.getLength() )
+ {
+ WritePS (mpJobHeader, "%%Title: (");
+ WritePS (mpJobHeader, aTitle);
+ WritePS (mpJobHeader, ")\n");
+ }
+
+ // Language Level
+ sal_Char pLevel[16];
+ sal_Int32 nSz = getValueOf(GetPostscriptLevel(&rSetupData), pLevel);
+ pLevel[nSz++] = '\n';
+ pLevel[nSz ] = '\0';
+ WritePS (mpJobHeader, "%%LanguageLevel: ");
+ WritePS (mpJobHeader, pLevel);
+
+ // Other
+ WritePS (mpJobHeader, "%%DocumentData: Clean7Bit\n");
+ WritePS (mpJobHeader, "%%Pages: (atend)\n");
+ WritePS (mpJobHeader, "%%Orientation: (atend)\n");
+ WritePS (mpJobHeader, "%%PageOrder: Ascend\n");
+ WritePS (mpJobHeader, "%%EndComments\n");
+
+ // write Prolog
+ writeProlog (mpJobHeader, rSetupData);
+
+ // mark last job setup as not set
+ m_aLastJobData.m_pParser = NULL;
+ m_aLastJobData.m_aContext.setParser( NULL );
+
+ return sal_True;
+}
+
+sal_Bool
+PrinterJob::EndJob ()
+{
+ // no pages ? that really means no print job
+ if( maPageList.empty() )
+ return sal_False;
+
+ // write document setup (done here because it
+ // includes the accumulated fonts
+ if( mpJobHeader )
+ writeSetup( mpJobHeader, m_aDocumentJobData );
+ m_pGraphics->OnEndJob();
+ if( ! (mpJobHeader && mpJobTrailer) )
+ return sal_False;
+
+ // write document trailer according to Document Structuring Conventions (DSC)
+ rtl::OStringBuffer aTrailer(512);
+ aTrailer.append( "%%Trailer\n" );
+ aTrailer.append( "%%BoundingBox: 0 0 " );
+ aTrailer.append( (sal_Int32)mnMaxWidthPt );
+ aTrailer.append( " " );
+ aTrailer.append( (sal_Int32)mnMaxHeightPt );
+ if( mnLandscapes > mnPortraits )
+ aTrailer.append("\n%%Orientation: Landscape");
+ else
+ aTrailer.append("\n%%Orientation: Portrait");
+ aTrailer.append( "\n%%Pages: " );
+ aTrailer.append( (sal_Int32)maPageList.size() );
+ aTrailer.append( "\n%%EOF\n" );
+ WritePS (mpJobTrailer, aTrailer.getStr());
+
+ /*
+ * spool the set of files to their final destination, this is U**X dependent
+ */
+
+ FILE* pDestFILE = NULL;
+
+ /* create a destination either as file or as a pipe */
+ sal_Bool bSpoolToFile = maFileName.getLength() > 0 ? sal_True : sal_False;
+ if (bSpoolToFile)
+ {
+ const rtl::OString aFileName = rtl::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 == NULL )
+ {
+ close( nFile );
+ unlink( aFileName.getStr() );
+ return sal_False;
+ }
+ }
+ else
+ chmod( aFileName.getStr(), mnFileMode );
+ }
+ if (pDestFILE == NULL)
+ pDestFILE = fopen (aFileName.getStr(), "w");
+
+ if (pDestFILE == NULL)
+ return sal_False;
+ }
+ else
+ {
+ PrinterInfoManager& rPrinterInfoManager = PrinterInfoManager::get ();
+ pDestFILE = rPrinterInfoManager.startSpool( m_aLastJobData.m_aPrinterName, m_bQuickJob );
+ if (pDestFILE == NULL)
+ return sal_False;
+ }
+
+ /* spool the document parts to the destination */
+
+ sal_uChar pBuffer[ nBLOCKSIZE ];
+
+ AppendPS (pDestFILE, mpJobHeader, pBuffer);
+ mpJobHeader->close();
+
+ sal_Bool bSuccess = sal_True;
+ std::list< osl::File* >::iterator pPageBody;
+ std::list< osl::File* >::iterator pPageHead;
+ for (pPageBody = maPageList.begin(), pPageHead = maHeaderList.begin();
+ pPageBody != maPageList.end() && pPageHead != maHeaderList.end();
+ pPageBody++, pPageHead++)
+ {
+ if( *pPageHead )
+ {
+ osl::File::RC nError = (*pPageHead)->open(OpenFlag_Read);
+ if (nError == osl::File::E_None)
+ {
+ AppendPS (pDestFILE, *pPageHead, pBuffer);
+ (*pPageHead)->close();
+ }
+ }
+ else
+ bSuccess = sal_False;
+ if( *pPageBody )
+ {
+ osl::File::RC nError = (*pPageBody)->open(OpenFlag_Read);
+ if (nError == osl::File::E_None)
+ {
+ AppendPS (pDestFILE, *pPageBody, pBuffer);
+ (*pPageBody)->close();
+ }
+ }
+ else
+ bSuccess = sal_False;
+ }
+
+ AppendPS (pDestFILE, mpJobTrailer, pBuffer);
+ mpJobTrailer->close();
+
+ /* well done */
+
+ if (bSpoolToFile)
+ fclose (pDestFILE);
+ else
+ {
+ PrinterInfoManager& rPrinterInfoManager = PrinterInfoManager::get();
+ if (0 == rPrinterInfoManager.endSpool( m_aLastJobData.m_aPrinterName,
+ maJobTitle, pDestFILE, m_aDocumentJobData, true ))
+ {
+ bSuccess = sal_False;
+ }
+ }
+
+ return bSuccess;
+}
+
+sal_Bool
+PrinterJob::AbortJob ()
+{
+ m_pGraphics->OnEndJob();
+ return sal_False;
+}
+
+void
+PrinterJob::InitPaperSize (const JobData& rJobSetup)
+{
+ int nRes = rJobSetup.m_aContext.getRenderResolution ();
+
+ String 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 != NULL)
+ 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 = (double)72.0 / (double)mnResolution;
+ mfYScale = -1.0 * (double)72.0 / (double)mnResolution;
+}
+
+
+sal_Bool
+PrinterJob::StartPage (const JobData& rJobSetup)
+{
+ InitPaperSize (rJobSetup);
+
+ rtl::OUString aPageNo = rtl::OUString::valueOf ((sal_Int32)maPageList.size()+1); // sequential page number must start with 1
+ rtl::OUString aExt = aPageNo + rtl::OUString::createFromAscii (".ps");
+
+ osl::File* pPageHeader = CreateSpoolFile (
+ rtl::OUString::createFromAscii("psp_pghead"), aExt);
+ osl::File* pPageBody = CreateSpoolFile (
+ rtl::OUString::createFromAscii("psp_pgbody"), aExt);
+
+ maHeaderList.push_back (pPageHeader);
+ maPageList.push_back (pPageBody);
+
+ if( ! (pPageHeader && pPageBody) )
+ return sal_False;
+
+ // 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++;
+ }
+
+ sal_Char pBBox [256];
+ sal_Int32 nChar = 0;
+
+ nChar = psp::appendStr ("%%PageBoundingBox: ", pBBox);
+ nChar += psp::getValueOf (mnLMarginPt, pBBox + nChar);
+ nChar += psp::appendStr (" ", pBBox + nChar);
+ nChar += psp::getValueOf (mnBMarginPt, pBBox + nChar);
+ nChar += psp::appendStr (" ", pBBox + nChar);
+ nChar += psp::getValueOf (mnWidthPt - mnRMarginPt, pBBox + nChar);
+ nChar += psp::appendStr (" ", pBBox + nChar);
+ nChar += psp::getValueOf (mnHeightPt - mnTMarginPt, pBBox + nChar);
+ nChar += psp::appendStr ("\n", pBBox + nChar);
+
+ WritePS (pPageHeader, pBBox);
+
+ /* #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 == maPageList.size() )
+ {
+ m_aDocumentJobData = rJobSetup;
+ bWriteFeatures = false;
+ }
+
+ if ( writePageSetup( pPageHeader, rJobSetup, bWriteFeatures ) )
+ {
+ m_aLastJobData = rJobSetup;
+ return true;
+ }
+
+ return false;
+}
+
+sal_Bool
+PrinterJob::EndPage ()
+{
+ m_pGraphics->OnEndPage();
+
+ osl::File* pPageHeader = maHeaderList.back();
+ osl::File* pPageBody = maPageList.back();
+
+ if( ! (pPageBody && pPageHeader) )
+ return sal_False;
+
+ // copy page to paper and write page trailer according to DSC
+
+ sal_Char pTrailer[256];
+ sal_Int32 nChar = 0;
+ nChar = psp::appendStr ("grestore grestore\n", pTrailer);
+ nChar += psp::appendStr ("showpage\n", pTrailer + nChar);
+ nChar += psp::appendStr ("%%PageTrailer\n\n", pTrailer + nChar);
+ WritePS (pPageBody, pTrailer);
+
+ // this page is done for now, close it to avoid having too many open fd's
+
+ pPageHeader->close();
+ pPageBody->close();
+
+ return sal_True;
+}
+
+sal_uInt32
+PrinterJob::GetErrorCode ()
+{
+ /* TODO */
+ return 0;
+}
+
+struct less_ppd_key : public ::std::binary_function<double, double, bool>
+{
+ 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( " *" );
+ aFeature.append( OUStringToOString( pKey->getKey(), RTL_TEXTENCODING_ASCII_US ) );
+ aFeature.append( ' ' );
+ aFeature.append( OUStringToOString( pValue->m_aOption, RTL_TEXTENCODING_ASCII_US ) );
+ if( !bUseIncluseFeature )
+ {
+ aFeature.append( '\n' );
+ aFeature.append( OUStringToOString( pValue->m_aValue, RTL_TEXTENCODING_ASCII_US ) );
+ aFeature.append( "\n%%EndFeature" );
+ }
+ aFeature.append( "\n} stopped cleartomark\n" );
+ sal_uInt64 nWritten = 0;
+ return pFile->write( aFeature.getStr(), aFeature.getLength(), nWritten )
+ || nWritten != (sal_uInt64)aFeature.getLength() ? false : true;
+}
+
+bool PrinterJob::writeFeatureList( osl::File* pFile, const JobData& rJob, bool bDocumentSetup )
+{
+ bool bSuccess = true;
+ int i;
+
+ // 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 == NULL )
+ )
+ {
+ int 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::DocumentSetup )
+ bEmit = true;
+ }
+ if( pKey->getSetupType() == PPDKey::PageSetup ||
+ pKey->getSetupType() == PPDKey::AnySetup )
+ bEmit = true;
+ if( bEmit )
+ {
+ const PPDValue* pValue = rJob.m_aContext.getValue( pKey );
+ if( pValue
+ && pValue->m_eType == eInvocation
+ && ( m_aLastJobData.m_pParser == NULL
+ || 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.SearchAscii( "<<" ) != STRING_NOTFOUND )
+ ||
+ ( pValue->m_aValue.SearchAscii( ">>" ) != STRING_NOTFOUND );
+ 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");
+
+ sal_Char pTranslate [128];
+ sal_Int32 nChar = 0;
+
+ if( rJob.m_eOrientation == orientation::Portrait )
+ {
+ nChar = psp::appendStr ("gsave\n[", pTranslate);
+ nChar += psp::getValueOfDouble ( pTranslate + nChar, mfXScale, 5);
+ nChar += psp::appendStr (" 0 0 ", pTranslate + nChar);
+ nChar += psp::getValueOfDouble ( pTranslate + nChar, mfYScale, 5);
+ nChar += psp::appendStr (" ", pTranslate + nChar);
+ nChar += psp::getValueOf (mnRMarginPt, pTranslate + nChar);
+ nChar += psp::appendStr (" ", pTranslate + nChar);
+ nChar += psp::getValueOf (mnHeightPt-mnTMarginPt,
+ pTranslate + nChar);
+ nChar += psp::appendStr ("] concat\ngsave\n",
+ pTranslate + nChar);
+ }
+ else
+ {
+ nChar = psp::appendStr ("gsave\n", pTranslate);
+ nChar += psp::appendStr ("[ 0 ", pTranslate + nChar);
+ nChar += psp::getValueOfDouble ( pTranslate + nChar, -mfYScale, 5);
+ nChar += psp::appendStr (" ", pTranslate + nChar);
+ nChar += psp::getValueOfDouble ( pTranslate + nChar, mfXScale, 5);
+ nChar += psp::appendStr (" 0 ", pTranslate + nChar );
+ nChar += psp::getValueOfDouble ( pTranslate + nChar, mnLMarginPt, 5 );
+ nChar += psp::appendStr (" ", pTranslate + nChar);
+ nChar += psp::getValueOf (mnBMarginPt, pTranslate + nChar );
+ nChar += psp::appendStr ("] concat\ngsave\n",
+ pTranslate + nChar);
+ }
+
+ WritePS (pFile, pTranslate);
+
+ return bSuccess;
+}
+
+void PrinterJob::writeJobPatch( osl::File* pFile, const JobData& rJobData )
+{
+ if( ! PrinterInfoManager::get().getUseJobPatch() )
+ return;
+
+ const PPDKey* pKey = NULL;
+
+ if( rJobData.m_pParser )
+ pKey = rJobData.m_pParser->getKey( OUString( RTL_CONSTASCII_USTRINGPARAM( "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::list< 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.EqualsAscii( "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" );
+ }
+ }
+
+ patch_order.sort();
+ patch_order.unique();
+
+ while( patch_order.begin() != patch_order.end() )
+ {
+ // 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::valueOf( patch_order.front() ) ), false );
+ patch_order.pop_front();
+ }
+}
+
+bool 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 sal_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"
+ };
+ static const sal_Char pSO52CompatProlog[] = {
+ "%%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 /quoteright\n"
+ "/parenleft /parenright /asterisk /plus /comma /minus /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, m_pGraphics && m_pGraphics->getStrictSO52Compatibility() ? pSO52CompatProlog : pProlog);
+
+ return true;
+}
+
+bool PrinterJob::writeSetup( osl::File* pFile, const JobData& rJob )
+{
+ WritePS (pFile, "%%BeginSetup\n%\n");
+
+ // download fonts
+ std::list< rtl::OString > aFonts[2];
+ m_pGraphics->writeResources( pFile, aFonts[0], aFonts[1] );
+
+ for( int i = 0; i < 2; i++ )
+ {
+ if( !aFonts[i].empty() )
+ {
+ std::list< rtl::OString >::const_iterator it = aFonts[i].begin();
+ rtl::OStringBuffer aLine( 256 );
+ if( i == 0 )
+ aLine.append( "%%DocumentSuppliedResources: font " );
+ else
+ aLine.append( "%%DocumentNeededResources: font " );
+ aLine.append( *it );
+ aLine.append( "\n" );
+ WritePS ( pFile, aLine.getStr() );
+ while( (++it) != aFonts[i].end() )
+ {
+ aLine.setLength(0);
+ aLine.append( "%%+ font " );
+ aLine.append( *it );
+ aLine.append( "\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
+ ByteString aLine( "/#copies " );
+ aLine += ByteString::CreateFromInt32( rJob.m_nCopies );
+ aLine += " def\n";
+ sal_uInt64 nWritten = 0;
+ bSuccess = pFile->write( aLine.GetBuffer(), aLine.Len(), nWritten )
+ || nWritten != aLine.Len() ? false : true;
+
+ 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;
+}
diff --git a/vcl/unx/generic/printergfx/psheader.ps b/vcl/unx/generic/printergfx/psheader.ps
new file mode 100644
index 000000000000..6a0e350d9ddc
--- /dev/null
+++ b/vcl/unx/generic/printergfx/psheader.ps
@@ -0,0 +1,368 @@
+%*************************************************************************
+%
+% DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+%
+% Copyright 2000, 2010 Oracle and/or its affiliates.
+%
+% OpenOffice.org - a multi-platform office productivity suite
+%
+% This file is part of OpenOffice.org.
+%
+% OpenOffice.org is free software: you can redistribute it and/or modify
+% it under the terms of the GNU Lesser General Public License version 3
+% only, as published by the Free Software Foundation.
+%
+% OpenOffice.org is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+% GNU Lesser General Public License version 3 for more details
+% (a copy is included in the LICENSE file that accompanied this code).
+%
+% You should have received a copy of the GNU Lesser General Public License
+% version 3 along with OpenOffice.org. If not, see
+% <http://www.openoffice.org/license.html>
+% for a copy of the LGPLv3 License.
+%
+%*************************************************************************
+
+%
+%
+% readpath
+%
+% The intention of readpath is to save disk space since the vcl clip region routines
+% produce a huge amount of lineto/moveto commands
+%
+% The principal idea is to maintain the current point on stack and to provide only deltas
+% in the command. These deltas are added to the current point. The new point is used for
+% the lineto and moveto command and saved on stack for the next command.
+%
+% pathdict implements binary/hex representation of lineto and moveto commands.
+% The command consists of a 1byte opcode to switch between lineto and moveto and the size
+% of the following delta-x and delta-y values. The opcode is read with /rcmd, the two
+% coordinates are read with /rhex. The whole command is executed with /xcmd
+%
+%
+
+/pathdict dup 8 dict def load
+begin
+
+ % the command is of the bit format cxxyy
+ % with c=0 meaning lineto
+ % c=1 meaning moveto
+ % xx is a 2bit value for the number of bytes for x position
+ % yy is the same for y, values are off by one: 00 means 1; 11 means 4 !
+ % the command has been added to 'A' to be always in the ascii character
+ % range. the command is followed by 2*xx + 2*yy hexchars.
+ % '~' denotes the special case of EOD
+ /rcmd {
+ {
+ currentfile 1 string readstring % s bool
+ pop % s
+ 0 get % s[0]
+ % --- check wether s[0] is CR, LF ...
+ dup 32 gt % s > ' ' ? then read on
+ { exit }
+ { pop }
+ ifelse
+ }
+ loop
+
+ dup 126 eq { pop exit } if % -- Exit loop if cmd is '~'
+ 65 sub % cmd=s[0]-'A'
+ % -- Separate yy bits
+ dup 16#3 and 1 add % cmd yy
+ % -- Separate xx bits
+ exch % yy cmd
+ dup 16#C and -2 bitshift
+ 16#3 and 1 add exch % yy xx cmd
+ % -- Separate command bit
+ 16#10 and 16#10 eq % yy xx bool
+ 3 1 roll exch % bool xx yy
+ } def
+
+ % length rhex -- reads a signed hex value of given length
+ % the left most bit of char 0 is considered as the sign (0 means '+', 1 means '-')
+ % the rest of the bits is considered to be the abs value. Please note that this
+ % does not match the C binary representation of integers
+ /rhex {
+ dup 1 sub exch % l-1 l
+ currentfile exch string readhexstring % l-1 substring[l] bool
+ pop
+ dup 0 get dup % l-1 s s[0] s[0]
+ % -- Extract the sign
+ 16#80 and 16#80 eq dup % l-1 s s[0] sign=- sign=-
+ % -- Mask out the sign bit and put value back
+ 3 1 roll % l-1 s sign=- s[0] sign=-
+ { 16#7f and } if % l-1 s sign=- +s[0]
+ 2 index 0 % l-1 s sign=- +s[0] s 0
+ 3 -1 roll put % l-1 s sign=- s 0 +s[0]
+ % -- Read loop: add to prev sum, mul with 256
+ 3 1 roll 0 % sign=- l-1 s Sum=0
+ 0 1 5 -1 roll % sign=- s Sum=0 0 1 l-1
+ { % sign=- s Sum idx
+ 2 index exch % sign=- s Sum s idx
+ get % sign=- s Sum s[idx]
+ add 256 mul % sign=- s Sum=(s[idx]+Sum)*256
+ }
+ for
+ % -- mul was once too often, weave in the sign
+ 256 div % sign=- s Sum/256
+ exch pop % sign=- Sum/256
+ exch { neg } if % (sign=- ? -Sum : Sum)
+ } def
+
+ % execute a single command, the former x and y position is already on stack
+ % only offsets are read from cmdstring
+ /xcmd { % x y
+ rcmd % x y bool wx wy
+ exch rhex % x y bool wy Dx
+ exch rhex % x y bool Dx Dy
+ exch 5 -1 roll % y bool Dy Dx x
+ add exch % y bool X Dy
+ 4 -1 roll add % bool X Y
+ 1 index 1 index % bool X Y X Y
+ 5 -1 roll % X Y X Y bool
+ { moveto }
+ { lineto }
+ ifelse % X Y
+ } def
+end
+
+/readpath
+{
+ 0 0 % push initial-x initial-y
+ pathdict begin
+ { xcmd } loop
+ end
+ pop pop % pop final-x final-y
+} def
+
+%
+%
+% if languagelevel is not in the systemdict then its level 1 interpreter:
+% provide compatibility routines
+%
+%
+
+systemdict /languagelevel known not
+{
+ % string numarray xxshow -
+ % does only work for single byte fonts
+ /xshow {
+ exch dup % a s s
+ length 0 1 % a s l(s) 1 1
+ 3 -1 roll 1 sub % a s 0 1 l(s)-1
+ { % a s idx
+ dup % a s idx idx
+ % -- extract the delta offset
+ 3 index exch get % a s idx a[idx]
+ % -- extract the character
+ exch % a s a[idx] idx
+ 2 index exch get % a s a[idx] s[idx]
+ % -- create a tmp string for show
+ 1 string dup 0 % a s a[idx] s[idx] s1 s1 0
+ 4 -1 roll % a s a[idx] s1 s1 0 s[idx]
+ put % a s a[idx] s1
+ % -- store the current point
+ currentpoint 3 -1 roll % a s a[idx] x y s1
+ % -- draw the character
+ show % a s a[idx] x y
+ % -- move to the offset
+ moveto 0 rmoveto % a s
+ }
+ for
+ pop pop % -
+ } def
+
+ % x y width height rectfill
+ % x y width height rectshow
+ % in contrast to the languagelevel 2 operator
+ % they use and change the currentpath
+ /rectangle {
+ 4 -2 roll % width height x y
+ moveto % width height
+ 1 index 0 rlineto % width height % rmoveto(width, 0)
+ 0 exch rlineto % width % rmoveto(0, height)
+ neg 0 rlineto % - % rmoveto(-width, 0)
+ closepath
+ } def
+
+ /rectfill { rectangle fill } def
+ /rectstroke { rectangle stroke } def
+}
+if
+
+% -- small test program
+% 75 75 moveto /Times-Roman findfont 12 scalefont setfont
+% <292a2b2c2d2e2f30313233343536373839>
+% [5 5 6 6 6 6 6 6 6 6 6 6 7 7 7 7 5] xshow <21>[0] xshow
+% showpage
+
+%
+%
+% shortcuts for image header with compression
+%
+%
+
+/psp_lzwfilter {
+ currentfile /ASCII85Decode filter /LZWDecode filter
+} def
+/psp_ascii85filter {
+ currentfile /ASCII85Decode filter
+} def
+/psp_lzwstring {
+ psp_lzwfilter 1024 string readstring
+} def
+/psp_ascii85string {
+ psp_ascii85filter 1024 string readstring
+} def
+/psp_imagedict {
+ /psp_bitspercomponent {
+ 3 eq
+ { 1 }
+ { 8 }
+ ifelse
+ } def
+ /psp_decodearray {
+ [ [0 1 0 1 0 1] [0 255] [0 1] [0 255] ] exch get
+ } def
+
+ 7 dict dup
+ /ImageType 1 put dup
+ /Width 7 -1 roll put dup
+ /Height 5 index put dup
+ /BitsPerComponent 4 index
+ psp_bitspercomponent put dup
+ /Decode 5 -1 roll
+ psp_decodearray put dup
+ /ImageMatrix [1 0 0 1 0 0] dup
+ 5 8 -1 roll put put dup
+ /DataSource 4 -1 roll
+ 1 eq
+ { psp_lzwfilter }
+ { psp_ascii85filter }
+ ifelse put
+} def
+
+
+%
+%
+% font encoding and reencoding
+%
+%
+
+/ISO1252Encoding [
+ /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+ /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+ /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+ /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+ /space /exclam /quotedbl /numbersign /dollar /percent /ampersand /quotesingle
+ /parenleft /parenright /asterisk /plus /comma /hyphen /period /slash
+ /zero /one /two /three /four /five /six /seven
+ /eight /nine /colon /semicolon /less /equal /greater /question
+ /at /A /B /C /D /E /F /G
+ /H /I /J /K /L /M /N /O
+ /P /Q /R /S /T /U /V /W
+ /X /Y /Z /bracketleft /backslash /bracketright /asciicircum /underscore
+ /grave /a /b /c /d /e /f /g
+ /h /i /j /k /l /m /n /o
+ /p /q /r /s /t /u /v /w
+ /x /y /z /braceleft /bar /braceright /asciitilde /unused
+ /Euro /unused /quotesinglbase /florin /quotedblbase /ellipsis /dagger /daggerdbl
+ /circumflex /perthousand /Scaron /guilsinglleft /OE /unused /Zcaron /unused
+ /unused /quoteleft /quoteright /quotedblleft /quotedblright /bullet /endash /emdash
+ /tilde /trademark /scaron /guilsinglright /oe /unused /zcaron /Ydieresis
+ /space /exclamdown /cent /sterling /currency /yen /brokenbar /section
+ /dieresis /copyright /ordfeminine /guillemotleft /logicalnot /hyphen /registered /macron
+ /degree /plusminus /twosuperior /threesuperior /acute /mu /paragraph /periodcentered
+ /cedilla /onesuperior /ordmasculine /guillemotright /onequarter /onehalf /threequarters /questiondown
+ /Agrave /Aacute /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla
+ /Egrave /Eacute /Ecircumflex /Edieresis /Igrave /Iacute /Icircumflex /Idieresis
+ /Eth /Ntilde /Ograve /Oacute /Ocircumflex /Otilde /Odieresis /multiply
+ /Oslash /Ugrave /Uacute /Ucircumflex /Udieresis /Yacute /Thorn /germandbls
+ /agrave /aacute /acircumflex /atilde /adieresis /aring /ae /ccedilla
+ /egrave /eacute /ecircumflex /edieresis /igrave /iacute /icircumflex /idieresis
+ /eth /ntilde /ograve /oacute /ocircumflex /otilde /odieresis /divide
+ /oslash /ugrave /uacute /ucircumflex /udieresis /yacute /thorn /ydieresis
+] def
+
+% /fontname /encoding psp_findfont
+/psp_findfont {
+ exch dup % encoding fontname fontname
+ findfont % encoding fontname
+ dup length dict
+ begin
+ {
+ 1 index /FID ne
+ { def }
+ { pop pop }
+ ifelse
+ } forall
+ /Encoding 3 -1 roll def
+ currentdict
+ end
+ /psp_reencodedfont exch definefont
+} def
+
+% bshow shows a text in artificial bold
+% this is achieved by first showing the text
+% then stroking its outline over it with
+% the linewidth set to the second parameter
+% usage: (string) num bshow
+
+/bshow {
+ currentlinewidth % save current linewidth
+ 3 1 roll % move it to the last stack position
+ currentpoint % save the current point
+ 3 index % copy the string to show
+ show % show it
+ moveto % move to the original coordinates again
+ setlinewidth % set the linewidth
+ false charpath % create the outline path of the shown string
+ stroke % and stroke it
+ setlinewidth % reset the stored linewidth
+} def
+
+% bxshow shows a text with a delta array in artificial bold
+% that is it does what bshow does for show
+% usage: (string) [deltaarray] num bxshow
+
+/bxshow {
+ currentlinewidth % save linewidth
+ 4 1 roll % move it to the last stack position
+ setlinewidth % set the new linewidth
+ exch % exchange string and delta array
+ dup
+ length % get length of string
+ 1 sub % prepare parameters for {} for
+ 0 1
+ 3 -1 roll
+ {
+ 1 string % create a string object length 1
+ 2 index % get the text
+ 2 index % get charpos (for index variable)
+ get % have char value at charpos
+ 1 index % prepare string for put
+ exch
+ 0
+ exch
+ put % put into string of length 1
+ dup % duplicate the it
+ currentpoint % save current position
+ 3 -1 roll % prepare show
+ show % show the character
+ moveto % move back to beginning
+ currentpoint % save current position
+ 3 -1 roll % prepare outline path of character
+ false charpath
+ stroke % stroke it
+ moveto % move back
+ % now move to next point
+ 2 index % get advance array
+ exch % get charpos
+ get % get advance element
+ 0 rmoveto % advance current position
+ } for
+ pop pop % remove string and delta array
+ setlinewidth % restore linewidth
+} def
diff --git a/vcl/unx/generic/printergfx/psputil.cxx b/vcl/unx/generic/printergfx/psputil.cxx
new file mode 100644
index 000000000000..370114be47cb
--- /dev/null
+++ b/vcl/unx/generic/printergfx/psputil.cxx
@@ -0,0 +1,268 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <string.h>
+
+#include "psputil.hxx"
+
+#include "tools/debug.hxx"
+
+namespace psp {
+
+/*
+ * string convenience routines
+ */
+
+sal_Int32
+getHexValueOf (sal_Int32 nValue, sal_Char* pBuffer)
+{
+ const static sal_Char pHex [0x10] = {
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
+
+ pBuffer[0] = pHex [(nValue & 0xF0) >> 4];
+ pBuffer[1] = pHex [(nValue & 0x0F) ];
+
+ return 2;
+}
+
+sal_Int32
+getAlignedHexValueOf (sal_Int32 nValue, sal_Char* pBuffer)
+{
+ // get sign
+ sal_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;
+ while (nPrecision)
+ {
+ nPrecision -= getHexValueOf (nValue % 256, pBuffer + nPrecision - 2 );
+ nValue /= 256;
+ }
+
+ // set sign bit
+ if (bNegative)
+ {
+ switch (pBuffer[0])
+ {
+ case '0' : pBuffer[0] = '8'; break;
+ case '1' : pBuffer[0] = '9'; break;
+ case '2' : pBuffer[0] = 'A'; break;
+ case '3' : pBuffer[0] = 'B'; break;
+ case '4' : pBuffer[0] = 'C'; break;
+ case '5' : pBuffer[0] = 'D'; break;
+ case '6' : pBuffer[0] = 'E'; break;
+ case '7' : pBuffer[0] = 'F'; break;
+ default: DBG_ERROR("Already a signed value");
+ }
+ }
+
+ // report precision
+ return nRet;
+}
+
+
+sal_Int32
+getValueOf (sal_Int32 nValue, sal_Char* pBuffer)
+{
+ sal_Int32 nChar = 0;
+ if (nValue < 0)
+ {
+ pBuffer [nChar++] = '-';
+ nValue *= -1;
+ }
+ else
+ if (nValue == 0)
+ {
+ pBuffer [nChar++] = '0';
+ return nChar;
+ }
+
+ sal_Char pInvBuffer [32];
+ sal_Int32 nInvChar = 0;
+ while (nValue > 0)
+ {
+ pInvBuffer [nInvChar++] = '0' + nValue % 10;
+ nValue /= 10;
+ }
+ while (nInvChar > 0)
+ {
+ pBuffer [nChar++] = pInvBuffer [--nInvChar];
+ }
+
+ return nChar;
+}
+
+sal_Int32
+appendStr (const sal_Char* pSrc, sal_Char* pDst)
+{
+ sal_Int32 nBytes = strlen (pSrc);
+ strncpy (pDst, pSrc, nBytes + 1);
+
+ return nBytes;
+}
+
+sal_Int32
+appendStr (const sal_Char* pSrc, sal_Char* pDst, sal_Int32 nBytes)
+{
+ strncpy (pDst, pSrc, nBytes);
+ pDst [nBytes] = '\0';
+ return nBytes;
+}
+
+/*
+ * copy strings to file
+ */
+
+sal_Bool
+WritePS (osl::File* pFile, const sal_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;
+}
+
+sal_Bool
+WritePS (osl::File* pFile, const sal_Char* pString, sal_uInt64 nInLength)
+{
+ sal_uInt64 nOutLength = 0;
+
+ if (nInLength > 0 && pFile)
+ pFile->write (pString, nInLength, nOutLength);
+
+ return nInLength == nOutLength;
+}
+
+sal_Bool
+WritePS (osl::File* pFile, const rtl::OString &rString)
+{
+ sal_uInt64 nInLength = rString.getLength();
+ sal_uInt64 nOutLength = 0;
+
+ if (nInLength > 0 && pFile)
+ pFile->write (rString, nInLength, nOutLength);
+
+ return nInLength == nOutLength;
+}
+
+sal_Bool
+WritePS (osl::File* pFile, const rtl::OUString &rString)
+{
+ return WritePS (pFile, rtl::OUStringToOString(rString, RTL_TEXTENCODING_ASCII_US));
+}
+
+/*
+ * cache converter for use in postscript drawing routines
+ */
+
+ConverterFactory::ConverterFactory()
+{
+}
+
+ConverterFactory::~ConverterFactory ()
+{
+ for( std::map< rtl_TextEncoding, rtl_UnicodeToTextConverter >::const_iterator it = m_aConverters.begin(); it != m_aConverters.end(); ++it )
+ rtl_destroyUnicodeToTextConverter (it->second);
+}
+
+rtl_UnicodeToTextConverter
+ConverterFactory::Get (rtl_TextEncoding nEncoding)
+{
+ if (rtl_isOctetTextEncoding( nEncoding ))
+ {
+ std::map< rtl_TextEncoding, rtl_UnicodeToTextConverter >::const_iterator it =
+ m_aConverters.find( nEncoding );
+ rtl_UnicodeToTextConverter aConverter;
+ if (it == m_aConverters.end())
+ {
+ aConverter = rtl_createUnicodeToTextConverter (nEncoding);
+ m_aConverters[nEncoding] = aConverter;
+ }
+ else
+ aConverter = it->second;
+ return aConverter;
+ }
+ return NULL;
+}
+
+// wrapper for rtl_convertUnicodeToText that handles the usual cases for
+// textconversion in drawtext
+sal_Size
+ConverterFactory::Convert (const sal_Unicode *pText, int nTextLen,
+ sal_uChar *pBuffer, sal_Size nBufferSize, rtl_TextEncoding nEncoding)
+{
+ const sal_uInt32 nCvtFlags = RTL_UNICODETOTEXT_FLAGS_UNDEFINED_QUESTIONMARK
+ | RTL_UNICODETOTEXT_FLAGS_INVALID_QUESTIONMARK ;
+ sal_uInt32 nCvtInfo;
+ sal_Size nCvtChars;
+
+ rtl_UnicodeToTextConverter aConverter = Get (nEncoding);
+ rtl_UnicodeToTextContext aContext = rtl_createUnicodeToTextContext (aConverter);
+
+ sal_Size nSize = rtl_convertUnicodeToText (aConverter, aContext,
+ pText, nTextLen, (sal_Char*)pBuffer, nBufferSize,
+ nCvtFlags, &nCvtInfo, &nCvtChars);
+
+ rtl_destroyUnicodeToTextContext (aConverter, aContext);
+
+ return nSize;
+}
+
+ConverterFactory*
+GetConverterFactory ()
+{
+ static ConverterFactory* pCvt = NULL;
+
+ if (pCvt == NULL)
+ pCvt = new ConverterFactory;
+
+ return pCvt;
+}
+
+
+} /* namespace psp */
diff --git a/vcl/unx/generic/printergfx/psputil.hxx b/vcl/unx/generic/printergfx/psputil.hxx
new file mode 100644
index 000000000000..d4af41bb95ed
--- /dev/null
+++ b/vcl/unx/generic/printergfx/psputil.hxx
@@ -0,0 +1,78 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _PSPRINT_PRINTERUTIL_HXX_
+#define _PSPRINT_PRINTERUTIL_HXX_
+
+#include "osl/file.hxx"
+
+#include "rtl/ustring.hxx"
+#include "rtl/string.hxx"
+#include "rtl/tencinfo.h"
+#include "rtl/textcvt.h"
+
+#include <map>
+
+namespace psp {
+
+/*
+ * string convenience routines
+ * sizeof(pBuffer) must be at least 2 Bytes, 0x00 <= nValue <= 0xFF,
+ * effective buffer of get*ValueOf() is NOT NULL-terminated
+ */
+sal_Int32 getHexValueOf (sal_Int32 nValue, sal_Char* pBuffer);
+sal_Int32 getAlignedHexValueOf (sal_Int32 nValue, sal_Char* pBuffer);
+sal_Int32 getValueOf (sal_Int32 nValue, sal_Char* pBuffer);
+sal_Int32 appendStr (const sal_Char* pSrc, sal_Char* pDst);
+sal_Int32 appendStr (const sal_Char* pSrc, sal_Char* pDst, sal_Int32 nBytes);
+
+sal_Bool WritePS (osl::File* pFile, const sal_Char* pString);
+sal_Bool WritePS (osl::File* pFile, const sal_Char* pString, sal_uInt64 nInLength);
+sal_Bool WritePS (osl::File* pFile, const rtl::OString &rString);
+sal_Bool WritePS (osl::File* pFile, const rtl::OUString &rString);
+
+class ConverterFactory
+{
+
+public:
+ ConverterFactory();
+ ~ConverterFactory();
+ rtl_UnicodeToTextConverter Get (rtl_TextEncoding nEncoding);
+ sal_Size Convert (const sal_Unicode *pText, int nTextLen,
+ sal_uChar *pBuffer, sal_Size nBufferSize,
+ rtl_TextEncoding nEncoding);
+private:
+
+ std::map< rtl_TextEncoding, rtl_UnicodeToTextConverter > m_aConverters;
+};
+
+ConverterFactory* GetConverterFactory ();
+
+} /* namespace psp */
+
+#endif /* _PSPRINT_PRINTERUTIL_HXX_ */
+
diff --git a/vcl/unx/generic/printergfx/text_gfx.cxx b/vcl/unx/generic/printergfx/text_gfx.cxx
new file mode 100644
index 000000000000..7934821d4d70
--- /dev/null
+++ b/vcl/unx/generic/printergfx/text_gfx.cxx
@@ -0,0 +1,862 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <math.h>
+
+#include "psputil.hxx"
+#include "glyphset.hxx"
+
+#include "printergfx.hxx"
+#include "vcl/fontmanager.hxx"
+#include "vcl/helper.hxx"
+
+#include "osl/thread.h"
+
+#include "sal/alloca.h"
+
+using namespace psp ;
+
+namespace psp {
+/*
+ container for a font and its helper fonts:
+ 1st font is the font substitute e.g. helvetica substitutes arial on the printer
+ 2nd is the font itself
+ 3rd is a fallback font, usually a font with unicode glyph repertoir (e.g. andale)
+ symbol fonts (adobe-fontspecific) may need special glyphmapping
+ (symbol page vc. latin page)
+*/
+class Font3
+{
+ private:
+
+ #define Font3Size 3
+
+ fontID mpFont [Font3Size];
+ bool mbSymbol;
+
+ public:
+
+ fontID GetFont (int nIdx) const
+ { return nIdx < Font3Size ? mpFont[nIdx] : -1 ; }
+ bool IsSymbolFont () const
+ { return mbSymbol; }
+
+ Font3 (const PrinterGfx &rGfx);
+ ~Font3 () {}
+};
+
+Font3::Font3(const PrinterGfx &rGfx)
+{
+ mpFont[0] = rGfx.getFontSubstitute();
+ mpFont[1] = rGfx.GetFontID();
+ mpFont[2] = rGfx.getFallbackID();
+ // mpFont[2] = rGfx.GetFontID();
+
+ PrintFontManager &rMgr = PrintFontManager::get();
+ mbSymbol = mpFont[1] != -1 ?
+ rMgr.getFontEncoding(mpFont[1]) == RTL_TEXTENCODING_SYMBOL : false;
+}
+
+} // namespace psp
+
+static int getVerticalDeltaAngle( sal_Unicode nChar )
+{
+ int nAngle = 0;
+ if( ( nChar >= 0x1100 && nChar < 0x11fa ) ||
+ ( nChar >= 0x3000 && nChar < 0xfb00 ) ||
+ ( nChar >= 0xfe20 && nChar < 0xfe70 ) ||
+ ( nChar >= 0xff00 && nChar < 0xff64 )
+ )
+ {
+ /* #i52932# remember:
+ nChar == 0x2010 || nChar == 0x2015
+ nChar == 0x2016 || nChar == 0x2026
+
+ are nAngle = 0 also, but already handled in the first if
+ */
+ if( ( nChar >= 0x3008 && nChar < 0x3019 && nChar != 0x3012 ) ||
+ nChar == 0xff3b || nChar == 0xff3d ||
+ (nChar >= 0xff6b && nChar < 0xff64 ) ||
+ nChar == 0xffe3
+ )
+ nAngle = 0;
+ else if( nChar == 0x30fc )
+ nAngle = -900;
+ else
+ nAngle = 900;
+ }
+ return nAngle;
+}
+
+void
+PrinterGfx::PSUploadPS1Font (sal_Int32 nFontID)
+{
+ std::list< sal_Int32 >::iterator aFont;
+ // already in the document header ?
+ for (aFont = maPS1Font.begin(); aFont != maPS1Font.end(); ++aFont )
+ if( nFontID == *aFont )
+ return;
+
+ // no occurrenc yet, mark for download
+ // add the fontid to the list
+ maPS1Font.push_back (nFontID);
+}
+
+/*
+ * implement text handling printer routines,
+ */
+
+sal_uInt16
+PrinterGfx::SetFont(
+ sal_Int32 nFontID,
+ sal_Int32 nHeight,
+ sal_Int32 nWidth,
+ sal_Int32 nAngle,
+ bool bVertical,
+ bool bArtItalic,
+ bool bArtBold
+ )
+{
+ // font and encoding will be set by drawText again immediately
+ // before PSShowText
+ mnFontID = nFontID;
+ maVirtualStatus.maFont = rtl::OString();
+ maVirtualStatus.maEncoding = RTL_TEXTENCODING_DONTKNOW;
+ maVirtualStatus.mnTextHeight = nHeight;
+ maVirtualStatus.mnTextWidth = nWidth;
+ maVirtualStatus.mbArtItalic = bArtItalic;
+ maVirtualStatus.mbArtBold = bArtBold;
+ mnTextAngle = nAngle;
+ mbTextVertical = bVertical;
+
+ return 0;
+}
+
+sal_uInt16
+PrinterGfx::SetFallbackFont ( sal_Int32 nFontID )
+{
+ mnFallbackID = nFontID;
+ return 0;
+}
+
+void PrinterGfx::drawGlyphs(
+ const Point& rPoint,
+ sal_uInt32* pGlyphIds,
+ sal_Unicode* pUnicodes,
+ sal_Int16 nLen,
+ sal_Int32* pDeltaArray
+ )
+{
+
+ // draw the string
+ // search for a glyph set matching the set font
+ std::list< GlyphSet >::iterator aIter;
+ for (aIter = maPS3Font.begin(); aIter != maPS3Font.end(); aIter++)
+ if ( ((*aIter).GetFontID() == mnFontID)
+ && ((*aIter).IsVertical() == mbTextVertical))
+ {
+ (*aIter).DrawGlyphs (*this, rPoint, pGlyphIds, pUnicodes, nLen, pDeltaArray);
+ break;
+ }
+
+ // not found ? create a new one
+ if (aIter == maPS3Font.end())
+ {
+ maPS3Font.push_back (GlyphSet(mnFontID, mbTextVertical));
+ maPS3Font.back().DrawGlyphs (*this, rPoint, pGlyphIds, pUnicodes, nLen, pDeltaArray);
+ }
+}
+
+void PrinterGfx::DrawGlyphs(
+ const Point& rPoint,
+ sal_GlyphId* pGlyphIds,
+ sal_Unicode* pUnicodes,
+ sal_Int16 nLen,
+ sal_Int32* pDeltaArray
+ )
+{
+ if( nLen <= 0 )
+ return;
+
+ if ( !mrFontMgr.isFontDownloadingAllowed( mnFontID ) )
+ {
+ LicenseWarning(rPoint, pUnicodes, nLen, pDeltaArray);
+ return;
+ }
+
+ if( mrFontMgr.getFontType( mnFontID ) != fonttype::TrueType )
+ {
+ DrawText( rPoint, pUnicodes, nLen, pDeltaArray );
+ return;
+ }
+
+ // 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
+ sal_Int32 nCurrentTextAngle = mnTextAngle;
+ Point aPoint( rPoint );
+
+ if (nCurrentTextAngle != 0)
+ {
+ PSGSave ();
+ PSTranslate (rPoint);
+ PSRotate (nCurrentTextAngle);
+ mnTextAngle = 0;
+ aPoint = Point( 0, 0 );
+ }
+
+ if( mbTextVertical )
+ {
+ // vertical glyphs can have an additional rotation ... sigh.
+ // so break up text in chunks of normal glyphs and print out
+ // specially rotated glyphs extra
+ sal_uInt32* pTempGlyphIds = (sal_uInt32*)alloca(sizeof(sal_Int32)*nLen);
+ sal_Int32* pTempDelta = (sal_Int32*)alloca(sizeof(sal_Int32)*nLen);
+ sal_Unicode* pTempUnicodes = (sal_Unicode*)alloca(sizeof(sal_Unicode)*nLen);
+ sal_Int16 nTempLen = 0;
+ sal_Int32 nTempFirstDelta = 0;
+ Point aRotPoint;
+ 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;
+
+ for( sal_Int16 i = 0; i < nLen; i++ )
+ {
+ const sal_GlyphId nRot = pGlyphIds[i] & GF_ROTMASK;
+ if( nRot == GF_NONE )
+ {
+ pTempUnicodes[nTempLen] = pUnicodes[i];
+ pTempGlyphIds[nTempLen] = pGlyphIds[i];
+ if( nTempLen > 0 )
+ pTempDelta[nTempLen-1] = pDeltaArray[i-1]-nTempFirstDelta;
+ else
+ {
+ // the first element in pDeltaArray shows
+ // the offset of the second character
+ // so if the first glyph is normal
+ // then we do not need to move the delta indices
+ // else we have to move them down by one and
+ // recalculate aPoint and all deltas
+ if( i != 0 )
+ nTempFirstDelta = pDeltaArray[ i-1 ];
+ }
+ nTempLen++;
+ }
+ else
+ {
+ sal_Int32 nOffset = i > 0 ? pDeltaArray[i-1] : 0;
+ sal_Int32 nRotAngle = 0;
+ switch( nRot )
+ {
+ case GF_ROTR:
+ nRotAngle = 2700;
+ aRotPoint = Point( -nAscend*nTextWidth/nTextHeight, -nDescend*nTextWidth/nTextHeight - nOffset );
+ break;
+ case GF_VERT:
+ nRotAngle = 1800;
+ aRotPoint = Point( -nOffset, (nAscend+nDescend) );
+ break;
+ case GF_ROTL:
+ nRotAngle = 900;
+ aRotPoint = Point( -nDescend*nTextWidth/nTextHeight, nOffset + nAscend*nTextWidth/nTextHeight );
+ break;
+ }
+ sal_GlyphId nRotGlyphId = pGlyphIds[i];
+ sal_Unicode nRotUnicode = pUnicodes[i];
+ sal_Int32 nRotDelta = 0;
+
+ // transform matrix to new individual direction
+ PSGSave ();
+ GraphicsStatus aSaveStatus = maVirtualStatus;
+ if( nRot != 2 ) // switch font aspect
+ {
+ maVirtualStatus.mnTextWidth = nTextHeight;
+ maVirtualStatus.mnTextHeight = nTextWidth;
+ }
+ if( aPoint.X() || aPoint.Y() )
+ PSTranslate( aPoint );
+ PSRotate (nRotAngle);
+ // draw the rotated glyph
+ drawGlyphs( aRotPoint, &nRotGlyphId, &nRotUnicode, 1, &nRotDelta );
+
+ // restore previous state
+ maVirtualStatus = aSaveStatus;
+ PSGRestore();
+ }
+ }
+
+ pGlyphIds = pTempGlyphIds;
+ pUnicodes = pTempUnicodes;
+ pDeltaArray = pTempDelta;
+ nLen = nTempLen;
+
+ aPoint.X() += nTempFirstDelta;
+ }
+
+ if( nLen > 0 )
+ drawGlyphs( aPoint, pGlyphIds, pUnicodes, nLen, pDeltaArray );
+
+ // restore the user coordinate system
+ if (nCurrentTextAngle != 0)
+ {
+ PSGRestore ();
+ mnTextAngle = nCurrentTextAngle;
+ }
+}
+
+void
+PrinterGfx::DrawText (
+ const Point& rPoint,
+ const sal_Unicode* pStr,
+ sal_Int16 nLen,
+ const sal_Int32* pDeltaArray
+ )
+{
+ fontID nRestoreFont = mnFontID;
+
+ // setup font[substitutes] and map the string into the symbol area in case of
+ // symbol font
+ Font3 aFont(*this);
+ sal_Unicode *pEffectiveStr;
+ if ( aFont.IsSymbolFont() )
+ {
+ pEffectiveStr = (sal_Unicode*)alloca(nLen * sizeof(pStr[0]));
+ for (int i = 0; i < nLen; i++)
+ pEffectiveStr[i] = pStr[i] < 256 ? pStr[i] + 0xF000 : pStr[i];
+ }
+ else
+ {
+ pEffectiveStr = const_cast<sal_Unicode*>(pStr);
+ }
+
+ fontID *pFontMap = (fontID*) alloca(nLen * sizeof(fontID));
+ sal_Int32 *pCharWidth = (sal_Int32*) alloca(nLen * sizeof(sal_Int32));
+
+ for( int n = 0; n < nLen; n++ )
+ {
+ CharacterMetric aBBox;
+ pFontMap[n] = getCharMetric (aFont, pEffectiveStr[n], &aBBox);
+ pCharWidth[n] = getCharWidth (mbTextVertical, pEffectiveStr[n], &aBBox);
+ }
+
+ // setup a new delta array, use virtual resolution of 1000
+ sal_Int32* pNewDeltaArray = (sal_Int32*)alloca( sizeof( sal_Int32 )*nLen );
+ if ( pDeltaArray != 0)
+ {
+ for (int i = 0; i < nLen - 1; i++)
+ pNewDeltaArray[i] = 1000 * pDeltaArray[i];
+ pNewDeltaArray[nLen - 1] = 0;
+ }
+ else
+ {
+ pNewDeltaArray[0] = pCharWidth[0];
+ for (int i = 1; i < nLen; i++)
+ pNewDeltaArray[i] = pNewDeltaArray[i-1] + pCharWidth[i];
+ }
+
+ // 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
+ sal_Int32 nCurrentTextAngle = mnTextAngle;
+ sal_Int32 nCurrentPointX;
+ sal_Int32 nCurrentPointY;
+
+ if (nCurrentTextAngle != 0)
+ {
+ PSGSave ();
+ PSTranslate (rPoint);
+ PSRotate (nCurrentTextAngle);
+ mnTextAngle = 0;
+
+ nCurrentPointX = 0;
+ nCurrentPointY = 0;
+ }
+ else
+ {
+ nCurrentPointX = rPoint.X();
+ nCurrentPointY = rPoint.Y();
+ }
+
+ // draw the string
+ sal_Int32 nDelta = 0;
+ for (int nTo = 0; nTo < nLen; )
+ {
+ int nFrom = nTo;
+ fontID nFont = pFontMap[ nFrom ];
+
+ while ((nTo < nLen) && (nFont == pFontMap[nTo]))
+ {
+ pNewDeltaArray[ nTo ] = (sal_Int32)(((0.5 + pNewDeltaArray[ nTo ]) / 1000.0) - nDelta);
+ nTo++ ;
+ }
+
+ SetFont( nFont,
+ maVirtualStatus.mnTextHeight, maVirtualStatus.mnTextWidth,
+ mnTextAngle,
+ mbTextVertical,
+ maVirtualStatus.mbArtItalic,
+ maVirtualStatus.mbArtBold
+ );
+
+ if (mbTextVertical)
+ {
+ drawVerticalizedText(
+ Point(nCurrentPointX + nDelta, nCurrentPointY),
+ pEffectiveStr + nFrom, nTo - nFrom,
+ pNewDeltaArray + nFrom );
+ }
+ else
+ {
+ drawText(
+ Point(nCurrentPointX + nDelta, nCurrentPointY),
+ pEffectiveStr + nFrom, nTo - nFrom,
+ pDeltaArray == NULL ? NULL : pNewDeltaArray + nFrom );
+ }
+ nDelta += pNewDeltaArray[ nTo - 1 ];
+ }
+
+ // restore the user coordinate system
+ if (nCurrentTextAngle != 0)
+ {
+ PSGRestore ();
+ mnTextAngle = nCurrentTextAngle;
+ }
+
+ // restore the original font settings
+ SetFont( nRestoreFont,
+ maVirtualStatus.mnTextHeight, maVirtualStatus.mnTextWidth,
+ mnTextAngle, mbTextVertical,
+ maVirtualStatus.mbArtItalic,
+ maVirtualStatus.mbArtBold
+ );
+}
+
+void PrinterGfx::drawVerticalizedText(
+ const Point& rPoint,
+ const sal_Unicode* pStr,
+ sal_Int16 nLen,
+ const sal_Int32* pDeltaArray
+ )
+{
+ sal_Int32* pDelta = (sal_Int32*)alloca( nLen * sizeof(sal_Int32) );
+
+ int nTextScale = maVirtualStatus.mnTextWidth ? maVirtualStatus.mnTextWidth : maVirtualStatus.mnTextHeight;
+ int nNormalAngle = mnTextAngle;
+ int nDeltaAngle, nLastPos = 0;
+
+ double fSin = sin( -2.0*M_PI*nNormalAngle/3600 );
+ double fCos = cos( -2.0*M_PI*nNormalAngle/3600 );
+
+ PrintFontManager &rMgr = PrintFontManager::get();
+ PrintFontInfo aInfo;
+ rMgr.getFontInfo( mnFontID, aInfo );
+
+ bool* pGsubFlags = (bool*)alloca( nLen * sizeof(bool) );
+ rMgr.hasVerticalSubstitutions( mnFontID, pStr, nLen, pGsubFlags );
+
+ Point aPoint( rPoint );
+ for( int i = 0; i < nLen; )
+ {
+ while( ( nDeltaAngle = getVerticalDeltaAngle( pStr[i] ) ) == 0 && i < nLen )
+ i++;
+ if( i <= nLen && i > nLastPos )
+ {
+ for( int n = nLastPos; n < i; n++ )
+ pDelta[n] = pDeltaArray[n] - (aPoint.X() - rPoint.X() );
+
+ SetFont( mnFontID,
+ maVirtualStatus.mnTextHeight, maVirtualStatus.mnTextWidth,
+ nNormalAngle, mbTextVertical,
+ maVirtualStatus.mbArtItalic,
+ maVirtualStatus.mbArtBold );
+ drawText( aPoint, pStr + nLastPos, i - nLastPos, pDelta + nLastPos );
+
+ aPoint.X() = (sal_Int32)(rPoint.X() + ((double)pDeltaArray[i-1] * fCos));
+ aPoint.Y() = (sal_Int32)(rPoint.Y() + ((double)pDeltaArray[i-1] * fSin));
+ }
+ if( i < nLen )
+ {
+ int nOldWidth = maVirtualStatus.mnTextWidth;
+ int nOldHeight = maVirtualStatus.mnTextHeight;
+ SetFont( mnFontID,
+ nTextScale,
+ maVirtualStatus.mnTextHeight,
+ nNormalAngle + nDeltaAngle,
+ mbTextVertical,
+ maVirtualStatus.mbArtItalic,
+ maVirtualStatus.mbArtBold );
+
+ double nA = nTextScale * aInfo.m_nAscend / 1000.0;
+ double nD = nTextScale * aInfo.m_nDescend / 1000.0;
+ double fStretch = (double)maVirtualStatus.mnTextWidth / maVirtualStatus.mnTextHeight;
+ if( !pGsubFlags[i] )
+ nD *= fStretch;
+
+ Point aPos( aPoint );
+ switch( nDeltaAngle )
+ {
+ case +900:
+ aPos.X() += (sal_Int32)(+nA * fCos + nD * fSin);
+ aPos.Y() += (sal_Int32)(-nA * fSin + nD * fCos);
+ break;
+ case -900:
+ aPos.X() += (sal_Int32)(+nA * fSin + nD * fCos);
+ aPos.Y() += (sal_Int32)(-(nTextScale*fStretch - nD) * fCos);
+ break;
+ }
+ drawText( aPos, pStr+i, 1, NULL );
+ if( i < nLen-1 && pDeltaArray )
+ {
+ aPoint.X() = (sal_Int32)(rPoint.X() + ((double)pDeltaArray[i] * fCos));
+ aPoint.Y() = (sal_Int32)(rPoint.Y() + ((double)pDeltaArray[i] * fSin));
+ }
+
+ // swap text width/height again
+ SetFont( mnFontID,
+ nOldHeight,
+ nOldWidth,
+ nNormalAngle,
+ mbTextVertical,
+ maVirtualStatus.mbArtItalic,
+ maVirtualStatus.mbArtBold );
+ }
+ i++;
+ nLastPos = i;
+ }
+ mnTextAngle = nNormalAngle;
+}
+
+void
+PrinterGfx::LicenseWarning(const Point& rPoint, const sal_Unicode* pStr,
+ sal_Int16 nLen, const sal_Int32* pDeltaArray)
+{
+ // treat it like a builtin font in case a user has that font also in the
+ // printer. This is not so unlikely as it may seem; no print embedding
+ // licensed fonts are often used (or so they say) in companies:
+ // they are installed on displays and printers, but get not embedded in
+ // they are installed on displays and printers, but get not embedded in
+ // print files or documents because they are not licensed for use outside
+ // the company.
+ rtl::OString aMessage( "The font " );
+ aMessage += rtl::OUStringToOString( mrFontMgr.getPSName(mnFontID),
+ RTL_TEXTENCODING_ASCII_US );
+ aMessage += " could not be downloaded\nbecause its license does not allow for that";
+ PSComment( aMessage.getStr() );
+
+ rtl::OString aFontName = rtl::OUStringToOString(
+ mrFontMgr.getPSName(mnFontID),
+ RTL_TEXTENCODING_ASCII_US);
+ PSSetFont (aFontName, RTL_TEXTENCODING_ISO_8859_1);
+
+ sal_Size nSize = 4 * nLen;
+ sal_uChar* pBuffer = (sal_uChar*)alloca (nSize* sizeof(sal_uChar));
+
+ ConverterFactory* pCvt = GetConverterFactory ();
+ nSize = pCvt->Convert (pStr, nLen, pBuffer, nSize, RTL_TEXTENCODING_ISO_8859_1);
+
+ PSMoveTo (rPoint);
+ PSShowText (pBuffer, nLen, nSize, pDeltaArray);
+}
+
+void
+PrinterGfx::drawText(
+ const Point& rPoint,
+ const sal_Unicode* pStr,
+ sal_Int16 nLen,
+ const sal_Int32* pDeltaArray
+ )
+{
+ if (!(nLen > 0))
+ return;
+
+ fonttype::type eType = mrFontMgr.getFontType (mnFontID);
+
+ if (eType == fonttype::Type1)
+ PSUploadPS1Font (mnFontID);
+
+ if ( eType == fonttype::TrueType
+ && !mrFontMgr.isFontDownloadingAllowed(mnFontID))
+ {
+ LicenseWarning(rPoint, pStr, nLen, pDeltaArray);
+ return;
+ }
+
+ if( mrFontMgr.getUseOnlyFontEncoding( mnFontID ) )
+ {
+ GlyphSet aGSet( mnFontID, mbTextVertical );
+ aGSet.DrawText( *this, rPoint, pStr, nLen, pDeltaArray );
+ return;
+ }
+
+ // search for a glyph set matching the set font
+ std::list< GlyphSet >::iterator aIter;
+ for (aIter = maPS3Font.begin(); aIter != maPS3Font.end(); aIter++)
+ if ( ((*aIter).GetFontID() == mnFontID)
+ && ((*aIter).IsVertical() == mbTextVertical))
+ {
+ (*aIter).DrawText (*this, rPoint, pStr, nLen, pDeltaArray);
+ break;
+ }
+
+ // not found ? create a new one
+ if (aIter == maPS3Font.end())
+ {
+ maPS3Font.push_back (GlyphSet(mnFontID, mbTextVertical));
+ maPS3Font.back().DrawText (*this, rPoint, pStr, nLen, pDeltaArray);
+ }
+}
+
+int
+PrinterGfx::getCharWidth (sal_Bool b_vert, sal_Unicode n_char, CharacterMetric *p_bbox)
+{
+ b_vert = b_vert && (getVerticalDeltaAngle(n_char) != 0);
+ int w = b_vert ? p_bbox->height : p_bbox->width;
+ w *= maVirtualStatus.mnTextWidth ? maVirtualStatus.mnTextWidth : maVirtualStatus.mnTextHeight;
+ return w;
+}
+
+fontID
+PrinterGfx::getCharMetric (const Font3 &rFont, sal_Unicode n_char, CharacterMetric *p_bbox)
+{
+ p_bbox->width = -1;
+ p_bbox->height = -1;
+
+ for (fontID n = 0; n < 3; n++)
+ {
+ fontID n_font = rFont.GetFont(n);
+ if (n_font != -1)
+ {
+ if( mbStrictSO52Compatibility )
+ {
+ fonttype::type eType = mrFontMgr.getFontType( n_font );
+ if( (eType == fonttype::Builtin || eType == fonttype::Type1) )
+ {
+ // note: any character exchanged here MUST also be changed
+ // in the compatibility ISO encoding vector in the prolog
+ // in printerjob.cxx
+ sal_Unicode aRepl = 0;
+ if( n_char == 0x2d )
+ aRepl = 0x2212;
+ else if( n_char == 0x27 )
+ aRepl = 0x2019;
+ /*
+ additional characters that may need backwards compatibility:
+ ISO5589 StdEnc Unicode suggested n_char -> aRepl
+ 0264 0302 0x00B4 0x00B4 (acute) -> 0x2019 (quiteright)
+ 0246 - 0x00A6 0x00A6 (brokenbar) -> 0x007C (bar)
+ 0225 0267 0x0095 0x0095 () -> 0x2022 (bullet)
+ 0140 0301 0x0060 0x0060 (grave) -> ?
+ */
+ if( aRepl )
+ {
+ mrFontMgr.getMetrics( n_font, aRepl, aRepl, p_bbox );
+ if (p_bbox->width >= 0 && p_bbox->height >= 0)
+ return n_font;
+ }
+ }
+ }
+ mrFontMgr.getMetrics( n_font, n_char, n_char, p_bbox );
+ }
+ if (p_bbox->width >= 0 && p_bbox->height >= 0)
+ return n_font;
+ }
+ if (n_char != '?')
+ return getCharMetric (rFont, '?', p_bbox);
+
+ return rFont.GetFont(0) != -1 ? rFont.GetFont(0) : rFont.GetFont(1);
+}
+
+fontID
+PrinterGfx::getFontSubstitute () const
+{
+ if( mpFontSubstitutes )
+ {
+ ::std::hash_map< fontID, fontID >::const_iterator it =
+ mpFontSubstitutes->find( mnFontID );
+ if( it != mpFontSubstitutes->end() )
+ return it->second;
+ }
+
+ return -1;
+}
+
+sal_Int32
+PrinterGfx::GetCharWidth (sal_Unicode nFrom, sal_Unicode nTo, long *pWidthArray)
+{
+ Font3 aFont(*this);
+ if (aFont.IsSymbolFont() && (nFrom < 256) && (nTo < 256))
+ {
+ nFrom += 0xF000;
+ nTo += 0xF000;
+ }
+
+ for( int n = 0; n < (nTo - nFrom + 1); n++ )
+ {
+ CharacterMetric aBBox;
+ getCharMetric (aFont, n + nFrom, &aBBox);
+ pWidthArray[n] = getCharWidth (mbTextVertical, n + nFrom, &aBBox);
+ }
+
+ // returned metrics have postscript precision
+ return 1000;
+}
+
+const ::std::list< KernPair >& PrinterGfx::getKernPairs( bool bVertical ) const
+{
+ /*
+ * Note: this is only a 80% solution: if a font is only
+ * partially substituted in a string due to missing glyphs
+ * the results may not be perfect; the more so the more the
+ * substitution differs from the original metricwise. But
+ * vcl only asks for KernPairs for each font once and NOT
+ * in a string context this is the best we can do.
+ * In future the kerning should be done on a per string basis.
+ */
+ fontID nFont = mnFontID;
+ if( mpFontSubstitutes )
+ {
+ ::std::hash_map< fontID, fontID >::const_iterator it =
+ mpFontSubstitutes->find( mnFontID );
+ if( it != mpFontSubstitutes->end() )
+ nFont = it->second;
+ }
+ return mrFontMgr.getKernPairs( nFont, bVertical );
+}
+
+/*
+ * advanced glyph handling
+ */
+
+sal_Bool
+PrinterGfx::GetGlyphBoundRect (sal_Unicode /*c*/, Rectangle& /*rOutRect*/)
+{
+ return 0;
+}
+
+sal_uInt32
+PrinterGfx::GetGlyphOutline (sal_Unicode /*c*/,
+ sal_uInt16 **/*ppPolySizes*/, Point **/*ppPoints*/, sal_uInt8 **/*ppFlags*/)
+{
+ return 0;
+}
+
+/*
+ * 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::OnEndPage ()
+{
+}
+
+void
+PrinterGfx::OnEndJob ()
+{
+ maPS3Font.clear();
+ maPS1Font.clear();
+}
+
+void
+PrinterGfx::writeResources( osl::File* pFile, std::list< rtl::OString >& rSuppliedFonts, std::list< rtl::OString >& rNeededFonts )
+{
+ // write all type 1 fonts
+ std::list< sal_Int32 >::iterator aFont;
+ // already in the document header ?
+ for (aFont = maPS1Font.begin(); aFont != maPS1Font.end(); ++aFont)
+ {
+ const rtl::OString& rSysPath (mrFontMgr.getFontFileSysPath(*aFont) );
+ rtl::OUString aUNCPath;
+ osl::File::getFileURLFromSystemPath (OStringToOUString (rSysPath, osl_getThreadTextEncoding()), aUNCPath);
+ osl::File aFontFile (aUNCPath);
+
+ // provide the pfb or pfa font as a (pfa-)font resource
+ rtl::OString aPostScriptName =
+ rtl::OUStringToOString ( mrFontMgr.getPSName(*aFont),
+ RTL_TEXTENCODING_ASCII_US );
+
+ WritePS (pFile, "%%BeginResource: font ");
+ WritePS (pFile, aPostScriptName.getStr());
+ WritePS (pFile, "\n");
+
+ osl::File::RC nError = aFontFile.open (OpenFlag_Read);
+ if (nError == osl::File::E_None)
+ {
+ convertPfbToPfa (aFontFile, *pFile);
+ aFontFile.close ();
+
+ pFile->setPos(osl_Pos_Current, -1);
+ char lastchar = '\n';
+ sal_uInt64 uBytes(1);
+ pFile->read((void *)(&lastchar), uBytes, uBytes);
+ if (lastchar != '\n')
+ WritePS (pFile, "\n");
+ }
+ WritePS (pFile, "%%EndResource\n");
+ rSuppliedFonts.push_back( aPostScriptName );
+ }
+
+ // write glyphsets and reencodings
+ std::list< GlyphSet >::iterator aIter;
+ for (aIter = maPS3Font.begin(); aIter != maPS3Font.end(); ++aIter)
+ {
+ if (aIter->GetFontType() == fonttype::TrueType)
+ {
+ aIter->PSUploadFont (*pFile, *this, mbUploadPS42Fonts ? true : false, rSuppliedFonts );
+ }
+ else
+ // ( aIter->GetFontType() == fonttype::Type1
+ // || aIter->GetFontType() == fonttype::Builtin )
+ {
+ aIter->PSUploadEncoding (pFile, *this);
+ if( aIter->GetFontType() == fonttype::Builtin )
+ rNeededFonts.push_back(
+ rtl::OUStringToOString(
+ mrFontMgr.getPSName( aIter->GetFontID() ),
+ RTL_TEXTENCODING_ASCII_US ) );
+ }
+ }
+}
+
+bool PrinterGfx::getStrictSO52Compatibility() const
+{
+ return mbStrictSO52Compatibility;
+}
+
+void PrinterGfx::setStrictSO52Compatibility( bool bCompat)
+{
+ mbStrictSO52Compatibility = bCompat;
+}