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