| /************************************************************** |
| * |
| * 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; |
| } |