Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include "glyphset.hxx"
21 : #include "psputil.hxx"
22 :
23 : #include "sft.hxx"
24 :
25 : #include "generic/printergfx.hxx"
26 : #include "fontsubset.hxx"
27 : #include "fontmanager.hxx"
28 :
29 : #include <tools/gen.hxx>
30 :
31 : #include "osl/thread.h"
32 :
33 : #include "sal/alloca.h"
34 :
35 : #include "rtl/ustring.hxx"
36 : #include "rtl/strbuf.hxx"
37 :
38 : #include <unotools/tempfile.hxx>
39 :
40 : #include <set>
41 : #include <map>
42 : #include <algorithm>
43 :
44 : using namespace vcl;
45 : using namespace psp;
46 :
47 0 : GlyphSet::GlyphSet (sal_Int32 nFontID, bool bVertical)
48 : : mnFontID (nFontID),
49 0 : mbVertical (bVertical)
50 : {
51 0 : PrintFontManager &rMgr = PrintFontManager::get();
52 0 : meBaseType = rMgr.getFontType (mnFontID);
53 0 : maBaseName = OUStringToOString (rMgr.getPSName(mnFontID),
54 0 : RTL_TEXTENCODING_ASCII_US);
55 0 : mnBaseEncoding = rMgr.getFontEncoding(mnFontID);
56 0 : mbUseFontEncoding = rMgr.getUseOnlyFontEncoding(mnFontID);
57 0 : }
58 :
59 0 : GlyphSet::~GlyphSet ()
60 : {
61 : /* FIXME delete the glyphlist ??? */
62 0 : }
63 :
64 : bool
65 0 : GlyphSet::GetCharID (
66 : sal_Unicode nChar,
67 : unsigned char* nOutGlyphID,
68 : sal_Int32* nOutGlyphSetID
69 : )
70 : {
71 0 : return LookupCharID (nChar, nOutGlyphID, nOutGlyphSetID)
72 0 : || AddCharID (nChar, nOutGlyphID, nOutGlyphSetID);
73 : }
74 :
75 : bool
76 0 : GlyphSet::GetGlyphID (
77 : sal_GlyphId nGlyph,
78 : sal_Unicode nUnicode,
79 : unsigned char* nOutGlyphID,
80 : sal_Int32* nOutGlyphSetID
81 : )
82 : {
83 0 : return LookupGlyphID (nGlyph, nOutGlyphID, nOutGlyphSetID)
84 0 : || AddGlyphID (nGlyph, nUnicode, nOutGlyphID, nOutGlyphSetID);
85 : }
86 :
87 : bool
88 0 : GlyphSet::LookupCharID (
89 : sal_Unicode nChar,
90 : unsigned char* nOutGlyphID,
91 : sal_Int32* nOutGlyphSetID
92 : )
93 : {
94 0 : char_list_t::iterator aGlyphSet;
95 : sal_Int32 nGlyphSetID;
96 :
97 : // loop through all the font subsets
98 0 : for (aGlyphSet = maCharList.begin(), nGlyphSetID = 1;
99 0 : aGlyphSet != maCharList.end();
100 : ++aGlyphSet, nGlyphSetID++)
101 : {
102 : // check every subset if it contains the queried unicode char
103 0 : char_map_t::const_iterator aGlyph = (*aGlyphSet).find (nChar);
104 0 : if (aGlyph != (*aGlyphSet).end())
105 : {
106 : // success: found the unicode char, return the glyphid and the glyphsetid
107 0 : *nOutGlyphSetID = nGlyphSetID;
108 0 : *nOutGlyphID = (*aGlyph).second;
109 0 : return true;
110 : }
111 : }
112 :
113 0 : *nOutGlyphSetID = -1;
114 0 : *nOutGlyphID = 0;
115 0 : return false;
116 : }
117 :
118 : bool
119 0 : GlyphSet::LookupGlyphID (
120 : sal_GlyphId nGlyph,
121 : unsigned char* nOutGlyphID,
122 : sal_Int32* nOutGlyphSetID
123 : )
124 : {
125 0 : glyph_list_t::iterator aGlyphSet;
126 : sal_Int32 nGlyphSetID;
127 :
128 : // loop through all the font subsets
129 0 : for (aGlyphSet = maGlyphList.begin(), nGlyphSetID = 1;
130 0 : aGlyphSet != maGlyphList.end();
131 : ++aGlyphSet, nGlyphSetID++)
132 : {
133 : // check every subset if it contains the queried unicode char
134 0 : glyph_map_t::const_iterator aGlyph = (*aGlyphSet).find (nGlyph);
135 0 : if (aGlyph != (*aGlyphSet).end())
136 : {
137 : // success: found the glyph id, return the mapped glyphid and the glyphsetid
138 0 : *nOutGlyphSetID = nGlyphSetID;
139 0 : *nOutGlyphID = (*aGlyph).second;
140 0 : return true;
141 : }
142 : }
143 :
144 0 : *nOutGlyphSetID = -1;
145 0 : *nOutGlyphID = 0;
146 0 : return false;
147 : }
148 :
149 : unsigned char
150 0 : GlyphSet::GetAnsiMapping (sal_Unicode nUnicodeChar)
151 : {
152 : static rtl_UnicodeToTextConverter aConverter =
153 0 : rtl_createUnicodeToTextConverter(RTL_TEXTENCODING_MS_1252);
154 : static rtl_UnicodeToTextContext aContext =
155 0 : rtl_createUnicodeToTextContext( aConverter );
156 :
157 : sal_Char nAnsiChar;
158 : sal_uInt32 nCvtInfo;
159 : sal_Size nCvtChars;
160 : const sal_uInt32 nCvtFlags = RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR
161 0 : | RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR;
162 :
163 : sal_Size nSize = rtl_convertUnicodeToText( aConverter, aContext,
164 : &nUnicodeChar, 1, &nAnsiChar, 1,
165 0 : nCvtFlags, &nCvtInfo, &nCvtChars );
166 :
167 0 : return nSize == 1 ? (unsigned char)nAnsiChar : (unsigned char)0;
168 : }
169 :
170 : unsigned char
171 0 : GlyphSet::GetSymbolMapping (sal_Unicode nUnicodeChar)
172 : {
173 0 : if (0x0000 < nUnicodeChar && nUnicodeChar < 0x0100)
174 0 : return (unsigned char)nUnicodeChar;
175 0 : if (0xf000 < nUnicodeChar && nUnicodeChar < 0xf100)
176 0 : return (unsigned char)nUnicodeChar;
177 :
178 0 : return 0;
179 : }
180 :
181 : void
182 0 : GlyphSet::AddNotdef (char_map_t &rCharMap)
183 : {
184 0 : if (rCharMap.empty())
185 0 : rCharMap[0] = 0;
186 0 : }
187 :
188 : void
189 0 : GlyphSet::AddNotdef (glyph_map_t &rGlyphMap)
190 : {
191 0 : if (rGlyphMap.empty())
192 0 : rGlyphMap[0] = 0;
193 0 : }
194 : bool
195 0 : GlyphSet::AddCharID (
196 : sal_Unicode nChar,
197 : unsigned char* nOutGlyphID,
198 : sal_Int32* nOutGlyphSetID
199 : )
200 : {
201 : unsigned char nMappedChar;
202 :
203 : // XXX important: avoid to reencode type1 symbol fonts
204 0 : if (mnBaseEncoding == RTL_TEXTENCODING_SYMBOL)
205 0 : nMappedChar = GetSymbolMapping (nChar);
206 : else
207 0 : nMappedChar = GetAnsiMapping (nChar);
208 :
209 : // create an empty glyphmap that is reserved for iso1252 encoded glyphs
210 : // (or -- unencoded -- symbol glyphs) and a second map that takes any other
211 0 : if (maCharList.empty())
212 : {
213 0 : char_map_t aMap, aMapp;
214 :
215 0 : maCharList.push_back (aMap);
216 0 : maCharList.push_back (aMapp);
217 : }
218 : // if the last map is full, create a new one
219 0 : if ((!nMappedChar) && (maCharList.back().size() == 255))
220 : {
221 0 : char_map_t aMap;
222 0 : maCharList.push_back (aMap);
223 : }
224 :
225 : // insert a new glyph in the font subset
226 0 : if (nMappedChar)
227 : {
228 : // always put iso1252 chars into the first map, map them on itself
229 0 : char_map_t& aGlyphSet = maCharList.front();
230 0 : AddNotdef (aGlyphSet);
231 :
232 0 : aGlyphSet [nChar] = nMappedChar;
233 0 : *nOutGlyphSetID = 1;
234 0 : *nOutGlyphID = nMappedChar;
235 : }
236 : else
237 : {
238 : // other chars are just appended to the list
239 0 : char_map_t& aGlyphSet = maCharList.back();
240 0 : AddNotdef (aGlyphSet);
241 :
242 0 : int nSize = aGlyphSet.size();
243 :
244 0 : aGlyphSet [nChar] = nSize;
245 0 : *nOutGlyphSetID = maCharList.size();
246 0 : *nOutGlyphID = aGlyphSet [nChar];
247 : }
248 :
249 0 : return true;
250 : }
251 :
252 : bool
253 0 : GlyphSet::AddGlyphID (
254 : sal_GlyphId nGlyph,
255 : sal_Unicode nUnicode,
256 : unsigned char* nOutGlyphID,
257 : sal_Int32* nOutGlyphSetID
258 : )
259 : {
260 0 : unsigned char nMappedChar = 0;
261 :
262 : // XXX important: avoid to reencode type1 symbol fonts
263 0 : if (mnBaseEncoding == RTL_TEXTENCODING_SYMBOL)
264 0 : nMappedChar = GetSymbolMapping (nUnicode);
265 :
266 : // create an empty glyphmap that is reserved for unencoded symbol glyphs,
267 : // and a second map that takes any other
268 0 : if (maGlyphList.empty())
269 : {
270 0 : glyph_map_t aMap, aMapp;
271 :
272 0 : maGlyphList.push_back (aMap);
273 0 : maGlyphList.push_back (aMapp);
274 : }
275 : // if the last map is full, create a new one
276 0 : if ((!nMappedChar) && (maGlyphList.back().size() == 255))
277 : {
278 0 : glyph_map_t aMap;
279 0 : maGlyphList.push_back (aMap);
280 : }
281 :
282 : // insert a new glyph in the font subset
283 0 : if (nMappedChar)
284 : {
285 : // always put symbol glyphs into the first map, map them on itself
286 0 : glyph_map_t& aGlyphSet = maGlyphList.front();
287 0 : AddNotdef (aGlyphSet);
288 :
289 0 : aGlyphSet [nGlyph] = nMappedChar;
290 0 : *nOutGlyphSetID = 1;
291 0 : *nOutGlyphID = nMappedChar;
292 : }
293 : else
294 : {
295 : // other glyphs are just appended to the list
296 0 : glyph_map_t& aGlyphSet = maGlyphList.back();
297 0 : AddNotdef (aGlyphSet);
298 :
299 0 : int nSize = aGlyphSet.size();
300 :
301 0 : aGlyphSet [nGlyph] = nSize;
302 0 : *nOutGlyphSetID = maGlyphList.size();
303 0 : *nOutGlyphID = aGlyphSet [nGlyph];
304 : }
305 :
306 0 : return true;
307 : }
308 :
309 : OString
310 0 : GlyphSet::GetCharSetName (sal_Int32 nGlyphSetID)
311 : {
312 0 : if (meBaseType == fonttype::TrueType)
313 : {
314 0 : OStringBuffer aSetName( maBaseName.getLength() + 32 );
315 0 : aSetName.append( maBaseName );
316 0 : aSetName.append( "FID" );
317 0 : aSetName.append( mnFontID );
318 0 : aSetName.append( mbVertical ? "VCSet" : "HCSet" );
319 0 : aSetName.append( nGlyphSetID );
320 0 : return aSetName.makeStringAndClear();
321 : }
322 : else
323 : {
324 0 : return maBaseName;
325 : }
326 : }
327 :
328 : OString
329 0 : GlyphSet::GetGlyphSetName (sal_Int32 nGlyphSetID)
330 : {
331 0 : if (meBaseType == fonttype::TrueType)
332 : {
333 0 : OStringBuffer aSetName( maBaseName.getLength() + 32 );
334 0 : aSetName.append( maBaseName );
335 0 : aSetName.append( "FID" );
336 0 : aSetName.append( mnFontID );
337 0 : aSetName.append( mbVertical ? "VGSet" : "HGSet" );
338 0 : aSetName.append( nGlyphSetID );
339 0 : return aSetName.makeStringAndClear();
340 : }
341 : else
342 : {
343 0 : return maBaseName;
344 : }
345 : }
346 :
347 : sal_Int32
348 0 : GlyphSet::GetGlyphSetEncoding (sal_Int32 nGlyphSetID)
349 : {
350 0 : if (meBaseType == fonttype::TrueType)
351 0 : return RTL_TEXTENCODING_DONTKNOW;
352 : else
353 : {
354 0 : if (mnBaseEncoding == RTL_TEXTENCODING_SYMBOL)
355 0 : return RTL_TEXTENCODING_SYMBOL;
356 : else
357 : return nGlyphSetID == 1 ? RTL_TEXTENCODING_MS_1252
358 0 : : RTL_TEXTENCODING_USER_START + nGlyphSetID;
359 : }
360 : }
361 :
362 : OString
363 0 : GlyphSet::GetGlyphSetEncodingName (rtl_TextEncoding nEnc, const OString &rFontName)
364 : {
365 0 : if ( nEnc == RTL_TEXTENCODING_MS_1252
366 0 : || nEnc == RTL_TEXTENCODING_ISO_8859_1)
367 : {
368 0 : return OString("ISO1252Encoding");
369 : }
370 : else
371 0 : if (nEnc >= RTL_TEXTENCODING_USER_START && nEnc <= RTL_TEXTENCODING_USER_END)
372 : {
373 : return rFontName
374 0 : + OString("Enc")
375 0 : + OString::number ((nEnc - RTL_TEXTENCODING_USER_START));
376 : }
377 : else
378 : {
379 0 : return OString();
380 : }
381 : }
382 :
383 : OString
384 0 : GlyphSet::GetGlyphSetEncodingName (sal_Int32 nGlyphSetID)
385 : {
386 0 : return GetGlyphSetEncodingName (GetGlyphSetEncoding(nGlyphSetID), maBaseName);
387 : }
388 :
389 : void
390 0 : GlyphSet::PSDefineReencodedFont (osl::File* pOutFile, sal_Int32 nGlyphSetID)
391 : {
392 : // only for ps fonts
393 0 : if (meBaseType != fonttype::Type1)
394 0 : return;
395 :
396 : sal_Char pEncodingVector [256];
397 0 : sal_Int32 nSize = 0;
398 :
399 0 : nSize += psp::appendStr ("(", pEncodingVector + nSize);
400 : nSize += psp::appendStr (GetReencodedFontName(nGlyphSetID).getStr(),
401 0 : pEncodingVector + nSize);
402 0 : nSize += psp::appendStr (") cvn (", pEncodingVector + nSize);
403 : nSize += psp::appendStr (maBaseName.getStr(),
404 0 : pEncodingVector + nSize);
405 0 : nSize += psp::appendStr (") cvn ", pEncodingVector + nSize);
406 : nSize += psp::appendStr (GetGlyphSetEncodingName(nGlyphSetID).getStr(),
407 0 : pEncodingVector + nSize);
408 : nSize += psp::appendStr (" psp_definefont\n",
409 0 : pEncodingVector + nSize);
410 :
411 0 : psp::WritePS (pOutFile, pEncodingVector);
412 : }
413 :
414 : OString
415 0 : GlyphSet::GetReencodedFontName (rtl_TextEncoding nEnc, const OString &rFontName)
416 : {
417 0 : if ( nEnc == RTL_TEXTENCODING_MS_1252
418 0 : || nEnc == RTL_TEXTENCODING_ISO_8859_1)
419 : {
420 : return rFontName
421 0 : + OString("-iso1252");
422 : }
423 : else
424 0 : if (nEnc >= RTL_TEXTENCODING_USER_START && nEnc <= RTL_TEXTENCODING_USER_END)
425 : {
426 : return rFontName
427 0 : + OString("-enc")
428 0 : + OString::number ((nEnc - RTL_TEXTENCODING_USER_START));
429 : }
430 : else
431 : {
432 0 : return OString();
433 : }
434 : }
435 :
436 : OString
437 0 : GlyphSet::GetReencodedFontName (sal_Int32 nGlyphSetID)
438 : {
439 0 : return GetReencodedFontName (GetGlyphSetEncoding(nGlyphSetID), maBaseName);
440 : }
441 :
442 0 : void GlyphSet::DrawGlyphs(
443 : PrinterGfx& rGfx,
444 : const Point& rPoint,
445 : const sal_GlyphId* pGlyphIds,
446 : const sal_Unicode* pUnicodes,
447 : sal_Int16 nLen,
448 : const sal_Int32* pDeltaArray,
449 : const bool bUseGlyphs)
450 : {
451 0 : unsigned char *pGlyphID = static_cast<unsigned char*>(alloca (nLen * sizeof(unsigned char)));
452 0 : sal_Int32 *pGlyphSetID = static_cast<sal_Int32*>(alloca (nLen * sizeof(sal_Int32)));
453 0 : std::set< sal_Int32 > aGlyphSet;
454 :
455 : // convert unicode to font glyph id and font subset
456 0 : for (int nChar = 0; nChar < nLen; nChar++)
457 : {
458 0 : if (bUseGlyphs)
459 0 : GetGlyphID (pGlyphIds[nChar], pUnicodes[nChar], pGlyphID + nChar, pGlyphSetID + nChar);
460 : else
461 0 : GetCharID (pUnicodes[nChar], pGlyphID + nChar, pGlyphSetID + nChar);
462 0 : aGlyphSet.insert (pGlyphSetID[nChar]);
463 : }
464 :
465 : // loop over all glyph sets to detect substrings that can be xshown together
466 : // without changing the postscript font
467 0 : sal_Int32 *pDeltaSubset = static_cast<sal_Int32*>(alloca (nLen * sizeof(sal_Int32)));
468 0 : unsigned char *pGlyphSubset = static_cast<unsigned char*>(alloca (nLen * sizeof(unsigned char)));
469 :
470 0 : std::set< sal_Int32 >::iterator aSet;
471 0 : for (aSet = aGlyphSet.begin(); aSet != aGlyphSet.end(); ++aSet)
472 : {
473 0 : Point aPoint = rPoint;
474 0 : sal_Int32 nOffset = 0;
475 0 : sal_Int32 nGlyphs = 0;
476 : sal_Int32 nChar;
477 :
478 : // get offset to first glyph
479 0 : for (nChar = 0; (nChar < nLen) && (pGlyphSetID[nChar] != *aSet); nChar++)
480 : {
481 0 : nOffset = pDeltaArray [nChar];
482 : }
483 :
484 : // loop over all chars to extract those that share the current glyph set
485 0 : for (nChar = 0; nChar < nLen; nChar++)
486 : {
487 0 : if (pGlyphSetID[nChar] == *aSet)
488 : {
489 0 : pGlyphSubset [nGlyphs] = pGlyphID [nChar];
490 : // the offset to the next glyph is determined by the glyph in
491 : // front of the next glyph with the same glyphset id
492 : // most often, this will be the current glyph
493 0 : while ((nChar + 1) < nLen)
494 : {
495 0 : if (pGlyphSetID[nChar + 1] == *aSet)
496 0 : break;
497 : else
498 0 : nChar += 1;
499 : }
500 0 : pDeltaSubset [nGlyphs] = pDeltaArray[nChar] - nOffset;
501 :
502 0 : nGlyphs += 1;
503 : }
504 : }
505 :
506 : // show the text using the PrinterGfx text api
507 0 : aPoint.Move (nOffset, 0);
508 :
509 0 : OString aGlyphSetName;
510 0 : if (bUseGlyphs)
511 0 : aGlyphSetName = GetGlyphSetName(*aSet);
512 : else
513 0 : aGlyphSetName = GetCharSetName(*aSet);
514 :
515 0 : rGfx.PSSetFont (aGlyphSetName, GetGlyphSetEncoding(*aSet));
516 0 : rGfx.PSMoveTo (aPoint);
517 0 : rGfx.PSShowText (pGlyphSubset, nGlyphs, nGlyphs, nGlyphs > 1 ? pDeltaSubset : NULL);
518 0 : }
519 0 : }
520 :
521 : void
522 0 : GlyphSet::DrawText (PrinterGfx &rGfx, const Point& rPoint,
523 : const sal_Unicode* pStr, sal_Int16 nLen, const sal_Int32* pDeltaArray)
524 : {
525 : // dispatch to the impl method
526 0 : if (pDeltaArray == NULL)
527 0 : ImplDrawText (rGfx, rPoint, pStr, nLen);
528 : else
529 0 : ImplDrawText (rGfx, rPoint, pStr, nLen, pDeltaArray);
530 0 : }
531 :
532 : void
533 0 : GlyphSet::ImplDrawText (PrinterGfx &rGfx, const Point& rPoint,
534 : const sal_Unicode* pStr, sal_Int16 nLen)
535 : {
536 0 : rGfx.PSMoveTo (rPoint);
537 :
538 0 : if( mbUseFontEncoding )
539 : {
540 0 : OString aPSName( OUStringToOString( rGfx.GetFontMgr().getPSName( mnFontID ), RTL_TEXTENCODING_ISO_8859_1 ) );
541 0 : OString aBytes( OUStringToOString( OUString( pStr, nLen ), mnBaseEncoding ) );
542 0 : rGfx.PSSetFont( aPSName, mnBaseEncoding );
543 0 : rGfx.PSShowText( reinterpret_cast<const unsigned char*>(aBytes.getStr()), nLen, aBytes.getLength() );
544 0 : return;
545 : }
546 :
547 : int nChar;
548 0 : unsigned char *pGlyphID = static_cast<unsigned char*>(alloca (nLen * sizeof(unsigned char)));
549 0 : sal_Int32 *pGlyphSetID = static_cast<sal_Int32*>(alloca (nLen * sizeof(sal_Int32)));
550 :
551 : // convert unicode to glyph id and char set (font subset)
552 0 : for (nChar = 0; nChar < nLen; nChar++)
553 0 : GetCharID (pStr[nChar], pGlyphID + nChar, pGlyphSetID + nChar);
554 :
555 : // loop over the string to draw subsequent pieces of chars
556 : // with the same postscript font
557 0 : for (nChar = 0; nChar < nLen; /* atend */)
558 : {
559 0 : sal_Int32 nGlyphSetID = pGlyphSetID [nChar];
560 0 : sal_Int32 nGlyphs = 1;
561 0 : for (int nNextChar = nChar + 1; nNextChar < nLen; nNextChar++)
562 : {
563 0 : if (pGlyphSetID[nNextChar] == nGlyphSetID)
564 0 : nGlyphs++;
565 : else
566 0 : break;
567 : }
568 :
569 : // show the text using the PrinterGfx text api
570 0 : OString aGlyphSetName(GetCharSetName(nGlyphSetID));
571 0 : rGfx.PSSetFont (aGlyphSetName, GetGlyphSetEncoding(nGlyphSetID));
572 0 : rGfx.PSShowText (pGlyphID + nChar, nGlyphs, nGlyphs);
573 :
574 0 : nChar += nGlyphs;
575 0 : }
576 : }
577 :
578 : void
579 0 : GlyphSet::ImplDrawText (PrinterGfx &rGfx, const Point& rPoint,
580 : const sal_Unicode* pStr, sal_Int16 nLen, const sal_Int32* pDeltaArray)
581 : {
582 0 : if( mbUseFontEncoding )
583 : {
584 0 : OString aPSName( OUStringToOString( rGfx.GetFontMgr().getPSName( mnFontID ), RTL_TEXTENCODING_ISO_8859_1 ) );
585 0 : OString aBytes( OUStringToOString( OUString( pStr, nLen ), mnBaseEncoding ) );
586 0 : rGfx.PSMoveTo( rPoint );
587 0 : rGfx.PSSetFont( aPSName, mnBaseEncoding );
588 0 : rGfx.PSShowText( reinterpret_cast<const unsigned char*>(aBytes.getStr()), nLen, aBytes.getLength(), pDeltaArray );
589 0 : return;
590 : }
591 :
592 0 : DrawGlyphs( rGfx, rPoint, NULL, pStr, nLen, pDeltaArray, false);
593 : }
594 :
595 : bool
596 0 : GlyphSet::PSUploadEncoding(osl::File* pOutFile, PrinterGfx &rGfx)
597 : {
598 : // only for ps fonts
599 0 : if (meBaseType != fonttype::Type1)
600 0 : return false;
601 0 : if (mnBaseEncoding == RTL_TEXTENCODING_SYMBOL)
602 0 : return false;
603 :
604 0 : PrintFontManager &rMgr = rGfx.GetFontMgr();
605 :
606 : // loop through all the font subsets
607 0 : sal_Int32 nGlyphSetID = 0;
608 0 : char_list_t::iterator aGlyphSet;
609 0 : for (aGlyphSet = maCharList.begin(); aGlyphSet != maCharList.end(); ++aGlyphSet)
610 : {
611 0 : ++nGlyphSetID;
612 :
613 0 : if (nGlyphSetID == 1) // latin1 page uses global reencoding table
614 : {
615 0 : PSDefineReencodedFont (pOutFile, nGlyphSetID);
616 0 : continue;
617 : }
618 0 : if ((*aGlyphSet).empty()) // empty set, doesn't need reencoding
619 : {
620 0 : continue;
621 : }
622 :
623 : // create reencoding table
624 :
625 : sal_Char pEncodingVector [256];
626 0 : sal_Int32 nSize = 0;
627 :
628 : nSize += psp::appendStr ("/",
629 0 : pEncodingVector + nSize);
630 : nSize += psp::appendStr (GetGlyphSetEncodingName(nGlyphSetID).getStr(),
631 0 : pEncodingVector + nSize);
632 : nSize += psp::appendStr (" [ ",
633 0 : pEncodingVector + nSize);
634 :
635 : // need a list of glyphs, sorted by glyphid
636 : typedef std::map< sal_uInt8, sal_Unicode > ps_mapping_t;
637 : typedef ps_mapping_t::value_type ps_value_t;
638 0 : ps_mapping_t aSortedGlyphSet;
639 :
640 0 : char_map_t::const_iterator aUnsortedGlyph;
641 0 : for (aUnsortedGlyph = (*aGlyphSet).begin();
642 0 : aUnsortedGlyph != (*aGlyphSet).end();
643 : ++aUnsortedGlyph)
644 : {
645 0 : aSortedGlyphSet.insert(ps_value_t((*aUnsortedGlyph).second,
646 0 : (*aUnsortedGlyph).first));
647 : }
648 :
649 0 : ps_mapping_t::const_iterator aSortedGlyph;
650 : // loop through all the glyphs in the subset
651 0 : for (aSortedGlyph = (aSortedGlyphSet).begin();
652 0 : aSortedGlyph != (aSortedGlyphSet).end();
653 : ++aSortedGlyph)
654 : {
655 : nSize += psp::appendStr ("/",
656 0 : pEncodingVector + nSize);
657 :
658 0 : std::list< OString > aName( rMgr.getAdobeNameFromUnicode((*aSortedGlyph).second) );
659 :
660 0 : if( aName.begin() != aName.end() )
661 0 : nSize += psp::appendStr ( aName.front().getStr(), pEncodingVector + nSize);
662 : else
663 0 : nSize += psp::appendStr (".notdef", pEncodingVector + nSize );
664 0 : nSize += psp::appendStr (" ", pEncodingVector + nSize);
665 : // flush line
666 0 : if (nSize >= 70)
667 : {
668 0 : psp::appendStr ("\n", pEncodingVector + nSize);
669 0 : psp::WritePS (pOutFile, pEncodingVector);
670 0 : nSize = 0;
671 : }
672 0 : }
673 :
674 0 : nSize += psp::appendStr ("] def\n", pEncodingVector + nSize);
675 0 : psp::WritePS (pOutFile, pEncodingVector);
676 :
677 0 : PSDefineReencodedFont (pOutFile, nGlyphSetID);
678 0 : }
679 :
680 0 : return true;
681 : }
682 :
683 : struct EncEntry
684 : {
685 : unsigned char aEnc;
686 : long aGID;
687 :
688 0 : EncEntry() : aEnc( 0 ), aGID( 0 ) {}
689 :
690 0 : bool operator<( const EncEntry& rRight ) const
691 0 : { return aEnc < rRight.aEnc; }
692 : };
693 :
694 0 : static void CreatePSUploadableFont( TrueTypeFont* pSrcFont, FILE* pTmpFile,
695 : const char* pGlyphSetName, int nGlyphCount,
696 : /*const*/ sal_uInt16* pRequestedGlyphs, /*const*/ unsigned char* pEncoding,
697 : bool bAllowType42, bool /*bAllowCID*/ )
698 : {
699 : // match the font-subset to the printer capabilities
700 : // TODO: allow CFF for capable printers
701 0 : int nTargetMask = FontSubsetInfo::TYPE1_PFA | FontSubsetInfo::TYPE3_FONT;
702 0 : if( bAllowType42 )
703 0 : nTargetMask |= FontSubsetInfo::TYPE42_FONT;
704 :
705 0 : std::vector< EncEntry > aSorted( nGlyphCount, EncEntry() );
706 0 : for( int i = 0; i < nGlyphCount; i++ )
707 : {
708 0 : aSorted[i].aEnc = pEncoding[i];
709 0 : aSorted[i].aGID = pRequestedGlyphs[i];
710 : }
711 :
712 0 : std::stable_sort( aSorted.begin(), aSorted.end() );
713 :
714 0 : std::vector< unsigned char > aEncoding( nGlyphCount );
715 0 : std::vector< sal_GlyphId > aRequestedGlyphs( nGlyphCount );
716 :
717 0 : for( int i = 0; i < nGlyphCount; i++ )
718 : {
719 0 : aEncoding[i] = aSorted[i].aEnc;
720 0 : aRequestedGlyphs[i] = aSorted[i].aGID;
721 : }
722 :
723 0 : FontSubsetInfo aInfo;
724 0 : aInfo.LoadFont( pSrcFont );
725 :
726 : aInfo.CreateFontSubset( nTargetMask, pTmpFile, pGlyphSetName,
727 0 : &aRequestedGlyphs[0], &aEncoding[0], nGlyphCount, NULL );
728 0 : }
729 :
730 : bool
731 0 : GlyphSet::PSUploadFont (osl::File& rOutFile, PrinterGfx &rGfx, bool bAllowType42, std::list< OString >& rSuppliedFonts )
732 : {
733 : // only for truetype fonts
734 0 : if (meBaseType != fonttype::TrueType)
735 0 : return false;
736 :
737 : #if defined( UNX )
738 : TrueTypeFont *pTTFont;
739 0 : OString aTTFileName (rGfx.GetFontMgr().getFontFileSysPath(mnFontID));
740 0 : int nFace = rGfx.GetFontMgr().getFontFaceNumber(mnFontID);
741 0 : sal_Int32 nSuccess = OpenTTFontFile(aTTFileName.getStr(), nFace, &pTTFont);
742 0 : if (nSuccess != SF_OK)
743 0 : return false;
744 :
745 0 : utl::TempFile aTmpFile;
746 0 : aTmpFile.EnableKillingFile();
747 0 : FILE* pTmpFile = fopen(OUStringToOString(aTmpFile.GetFileName(), osl_getThreadTextEncoding()).getStr(), "w+b");
748 0 : if (pTmpFile == NULL)
749 0 : return false;
750 :
751 : // array of unicode source characters
752 : sal_Unicode pUChars[256];
753 :
754 : // encoding vector maps character encoding to the ordinal number
755 : // of the glyph in the output file
756 : unsigned char pEncoding[256];
757 : sal_uInt16 pTTGlyphMapping[256];
758 0 : const bool bAllowCID = false; // TODO: nPSLanguageLevel>=3
759 :
760 : // loop through all the font subsets
761 : sal_Int32 nCharSetID;
762 0 : char_list_t::iterator aCharSet;
763 0 : for (aCharSet = maCharList.begin(), nCharSetID = 1;
764 0 : aCharSet != maCharList.end();
765 : ++aCharSet, nCharSetID++)
766 : {
767 0 : if ((*aCharSet).empty())
768 0 : continue;
769 :
770 : // loop through all the chars in the subset
771 0 : char_map_t::const_iterator aChar;
772 0 : sal_Int32 n = 0;
773 0 : for (aChar = (*aCharSet).begin(); aChar != (*aCharSet).end(); ++aChar)
774 : {
775 0 : pUChars [n] = (*aChar).first;
776 0 : pEncoding [n] = (*aChar).second;
777 0 : n++;
778 : }
779 : // create a mapping from the unicode chars to the char encoding in
780 : // source TrueType font
781 0 : MapString (pTTFont, pUChars, (*aCharSet).size(), pTTGlyphMapping, mbVertical);
782 :
783 : // create the current subset
784 0 : OString aCharSetName = GetCharSetName(nCharSetID);
785 0 : fprintf( pTmpFile, "%%%%BeginResource: font %s\n", aCharSetName.getStr() );
786 0 : CreatePSUploadableFont( pTTFont, pTmpFile, aCharSetName.getStr(), (*aCharSet).size(),
787 0 : pTTGlyphMapping, pEncoding, bAllowType42, bAllowCID );
788 0 : fprintf( pTmpFile, "%%%%EndResource\n" );
789 0 : rSuppliedFonts.push_back( aCharSetName );
790 0 : }
791 :
792 : // loop through all the font glyph subsets
793 : sal_Int32 nGlyphSetID;
794 0 : glyph_list_t::iterator aGlyphSet;
795 0 : for (aGlyphSet = maGlyphList.begin(), nGlyphSetID = 1;
796 0 : aGlyphSet != maGlyphList.end();
797 : ++aGlyphSet, nGlyphSetID++)
798 : {
799 0 : if ((*aGlyphSet).empty())
800 0 : continue;
801 :
802 : // loop through all the glyphs in the subset
803 0 : glyph_map_t::const_iterator aGlyph;
804 0 : sal_Int32 n = 0;
805 0 : for (aGlyph = (*aGlyphSet).begin(); aGlyph != (*aGlyphSet).end(); ++aGlyph)
806 : {
807 0 : pTTGlyphMapping [n] = (*aGlyph).first;
808 0 : pEncoding [n] = (*aGlyph).second;
809 0 : n++;
810 : }
811 :
812 : // create the current subset
813 0 : OString aGlyphSetName = GetGlyphSetName(nGlyphSetID);
814 0 : fprintf( pTmpFile, "%%%%BeginResource: font %s\n", aGlyphSetName.getStr() );
815 0 : CreatePSUploadableFont( pTTFont, pTmpFile, aGlyphSetName.getStr(), (*aGlyphSet).size(),
816 0 : pTTGlyphMapping, pEncoding, bAllowType42, bAllowCID );
817 0 : fprintf( pTmpFile, "%%%%EndResource\n" );
818 0 : rSuppliedFonts.push_back( aGlyphSetName );
819 0 : }
820 :
821 : // copy the file into the page header
822 0 : rewind(pTmpFile);
823 0 : fflush(pTmpFile);
824 :
825 : unsigned char pBuffer[0x2000];
826 : sal_uInt64 nIn;
827 : sal_uInt64 nOut;
828 0 : do
829 : {
830 0 : nIn = fread(pBuffer, 1, sizeof(pBuffer), pTmpFile);
831 0 : rOutFile.write (pBuffer, nIn, nOut);
832 : }
833 0 : while ((nIn == nOut) && !feof(pTmpFile));
834 :
835 : // cleanup
836 0 : CloseTTFont (pTTFont);
837 0 : fclose (pTmpFile);
838 :
839 0 : return true;
840 : #else
841 : (void)rOutFile; (void)rGfx; (void)bAllowType42; (void)rSuppliedFonts;
842 : # warning FIXME: Missing OpenTTFontFile outside of Unix ...
843 : return false;
844 : #endif
845 801 : }
846 :
847 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|