blob: da763dae2673cc498e42afb8b1d2356a04a6accc [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the 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_GlyphId 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_GlyphId 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_GlyphId 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_GlyphId* 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< sal_GlyphId> aRequestedGlyphs( nGlyphCount );
for( int i = 0; i < nGlyphCount; i++ )
{
aEncoding[i] = aSorted[i].aEnc;
aRequestedGlyphs[i] = aSorted[i].aGID;
}
FontSubsetInfo aInfo;
aInfo.LoadFont( pSrcFont );
aInfo.CreateFontSubset( nTargetMask, pTmpFile, pGlyphSetName,
&aRequestedGlyphs[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;
}