1 /************************************************************************/
2 /* */
3 /* Mapping between Document fonts and PostScript fonts. */
4 /* */
5 /************************************************************************/
6
7 # include "docFontConfig.h"
8
9 # include <string.h>
10
11 # include <appDebugon.h>
12 # include <psDocumentFontStyle.h>
13
14 # include "utilDocFont.h"
15 # include "utilMatchFont.h"
16 # include <textOfficeCharset.h>
17
18 /************************************************************************/
19 /* */
20 /* Map the RTF style faces to the actual faces of a PostScript font. */
21 /* */
22 /* 6) Remember what the face numbers of the variants of the font. */
23 /* 7) If no face number was found for plain, take an arbitrary one. */
24 /* 8) For all variants without a face number, take the plian one. */
25 /* (but see 7). */
26 /* */
27 /************************************************************************/
28
utilMatchPsFacesToDocFont(DocumentFont * df,const PsFontFamily * psf)29 static void utilMatchPsFacesToDocFont( DocumentFont * df,
30 const PsFontFamily * psf )
31 {
32 int fac;
33
34 /* 6 */
35 for ( fac= 0; fac < psf->psfFaceCount; fac++ )
36 {
37 int b= FONT_IS_BOLD( psf->psfFaces[fac] );
38 int s= FONT_IS_SLANTED( psf->psfFaces[fac] );
39
40 df->dfPsFontInfo[FACE_INDEX(s,b)]= psf->psfFaces[fac];
41 }
42
43 if ( ! df->dfPsFontInfo[0] )
44 {
45 for ( fac= 0; fac < FONTface_COUNT; fac++ )
46 {
47 if ( df->dfPsFontInfo[fac] )
48 { df->dfPsFontInfo[0]= df->dfPsFontInfo[fac]; break; }
49 }
50 }
51
52 for ( fac= 0; fac < FONTface_COUNT; fac++ )
53 {
54 if ( ! df->dfPsFontInfo[fac] )
55 { df->dfPsFontInfo[fac]= df->dfPsFontInfo[0]; }
56 }
57
58 return;
59 }
60
61 /************************************************************************/
62
63 /************************************************************************/
64 /* */
65 /* Temporarily add the PostScript fonts that we have on the machine to */
66 /* the font list of the document. As we only save the fonts that are */
67 /* actually used in the document, the number of fonts in the document */
68 /* will not grow every time it is opened in a different environment. */
69 /* */
70 /* Just insert the font as an ANSI font: The exact details only count */
71 /* once the font has been used and the document is saved. */
72 /* */
73 /************************************************************************/
74
utilAddPsFontsToDocList(DocumentFontList * dfl,const PostScriptFontList * psfl)75 int utilAddPsFontsToDocList( DocumentFontList * dfl,
76 const PostScriptFontList * psfl )
77 {
78 int fam;
79
80 for ( fam= 0; fam < psfl->psflFamilyCount; fam++ )
81 {
82 DocumentFont * df;
83 const PsFontFamily * aff= psfl->psflFamilies[fam];
84
85 int styleInt;
86 int pitch= FONTpitchDEFAULT;
87
88 styleInt= psFontFamilyStyle( aff->psfFontFamilyName );
89 if ( aff->psfHasFixedWidth )
90 { pitch= FONTpitchFIXED; }
91 if ( aff->psfHasProportionalWidth )
92 { pitch= FONTpitchVARIABLE; }
93
94 df= utilAddFontToDocList( dfl, aff->psfFontFamilyName,
95 styleInt, pitch );
96 if ( ! df )
97 { SXDEB(aff->psfFontFamilyName,df); return -1; }
98
99 utilMatchPsFacesToDocFont( df, aff );
100 }
101
102 return 0;
103 }
104
105 typedef struct Base35Family
106 {
107 const char * b35fName;
108 int b35fStyle;
109 } Base35Family;
110
111 # if 0
112 /*
113 136 font set:
114 http://www.adobe.com/products/postscript/pdfs/ps3fonts.pdf
115 */
116
117 { "Albertus", DFstyleFROMAN },
118 { "Antique Olive", DFstyleFSWISS },
119 { "Apple Chancery", DFstyleFSCRIPT },
120 { "Arial", DFstyleFSWISS },
121 { "Bodoni", DFstyleFROMAN },
122 { "Bodoni Compressed", DFstyleFROMAN },
123 { "Carta", DFstyleFSWISS },
124 { "Chicago", DFstyleFSWISS },
125 { "Clarendon", DFstyleFROMAN },
126 { "Cooper", DFstyleFROMAN },
127 { "Copperplate", DFstyleFSWISS },
128 { "Coronet", DFstyleFSCRIPT },
129 { "Eurostile", DFstyleFSWISS },
130 { "Eurostile Extended", DFstyleFSWISS },
131 { "Geneva", DFstyleFSWISS },
132 { "Gill Sans", DFstyleFSWISS },
133 { "Gill Sans Condensed", DFstyleFSWISS },
134 { "Goudy", DFstyleFROMAN },
135 { "Hoefler Text", DFstyleFROMAN },
136 { "Hoefler Ornaments", DFstyleFTECH },
137 { "Joanna", DFstyleFROMAN },
138 { "Letter", DFstyleFSWISS },
139 { "ITC Lubalin Graph", DFstyleFROMAN },
140 { "Marigold", DFstyleFSCRIPT },
141 { "Monaco", DFstyleFSWISS },
142 { "ITC Mona Lisa Recut", DFstyleFROMAN },
143 { "New York", DFstyleFROMAN },
144 { "Optima", DFstyleFSWISS },
145 { "Oxford", DFstyleFSCRIPT },
146 { "Stempel Garamond", DFstyleFROMAN },
147 { "Tekton", DFstyleFSCRIPT },
148 { "Times New Roman", DFstyleFROMAN },
149 { "Univers", DFstyleFSWISS },
150 { "Univers Condensed", DFstyleFSWISS },
151 { "Univers Extended", DFstyleFSWISS },
152 { "Wingdings", DFstyleFTECH },
153 # endif
154
155 static const Base35Family UtilBase35Families[]=
156 {
157 { "Courier", DFstyleFMODERN },
158 { "Helvetica", DFstyleFSWISS },
159 { "Helvetica Narrow", DFstyleFSWISS },
160 { "ITC Avant Garde Gothic", DFstyleFSWISS },
161 { "ITC Bookman", DFstyleFROMAN },
162 { "ITC Zapf Chancery", DFstyleFSCRIPT },
163 { "ITC Zapf Dingbats", DFstyleFTECH },
164 { "New Century Schoolbook", DFstyleFROMAN },
165 { "Palatino", DFstyleFROMAN },
166 { "Symbol", DFstyleFTECH },
167 { "Times", DFstyleFROMAN },
168 };
169 static const int UtilBase35FamilyCount=
170 sizeof(UtilBase35Families)/sizeof(Base35Family);
171
utilAddBase35FontsToDocList(DocumentFontList * dfl)172 int utilAddBase35FontsToDocList( DocumentFontList * dfl )
173 {
174 int fam;
175 const Base35Family * b35f= UtilBase35Families;
176
177 for ( fam= 0; fam < UtilBase35FamilyCount; b35f++, fam++ )
178 {
179 DocumentFont * df;
180 int pitch= FONTpitchVARIABLE;
181
182 if ( b35f->b35fStyle == DFstyleFMODERN )
183 { pitch= FONTpitchFIXED; }
184
185 df= utilAddFontToDocList( dfl, b35f->b35fName,
186 b35f->b35fStyle, pitch );
187 if ( ! df )
188 { SXDEB(b35f->b35fName,df); return -1; }
189 }
190
191 return 0;
192 }
193
194 /************************************************************************/
195 /* */
196 /* Return the mappings relating to a font. */
197 /* */
198 /* 1) Dingbats are a bit from the past that we still have to support. */
199 /* 2) For fonts without an encoding, assume the same encoding as the */
200 /* document. */
201 /* 3) But make an exception for yet another legacy font. */
202 /* */
203 /************************************************************************/
204
utilGetEncodingName(const char * fontName,int charset)205 const char * utilGetEncodingName( const char * fontName,
206 int charset )
207 {
208 const OfficeCharset * oc;
209 int charsetIdx;
210
211 /* 1 */
212 if ( ! strcmp( fontName, "ITC Zapf Dingbats" ) ||
213 ! strcmp( fontName, "ZapfDingbats" ) ||
214 ! strcmp( fontName, "Dingbats" ) )
215 { return "DINGBATS"; }
216
217 /* 3 */
218 if ( ! strcmp( fontName, "Symbol" ) )
219 { return "SYMBOL"; }
220
221 oc= utilGetOfficeCharsetByCharset( &charsetIdx, charset );
222 if ( ! oc )
223 { return (const char *)0; }
224
225 return oc->ocEncodingName;
226 }
227
228 /************************************************************************/
229 /* */
230 /* Find the set of encodings that best covers the unicode values in */
231 /* the document. */
232 /* */
233 /* Use a naive implementation of the 'Greedy Set Cover' algorithm. */
234 /* */
235 /************************************************************************/
236
237 typedef struct FontCharset
238 {
239 DocumentFont * fcFont;
240 int fcCharsetIdx;
241 } FontCharset;
242
docFontSetUnicodeCharsetIdx(int unicode,void * vfc)243 static int docFontSetUnicodeCharsetIdx( int unicode,
244 void * vfc )
245 {
246 const FontCharset * fc= (const FontCharset *)vfc;
247
248 if ( utilIndexMappingPut( &(fc->fcFont->dfUnicodeToCharset),
249 unicode, fc->fcCharsetIdx ) )
250 { LLDEB(unicode,fc->fcCharsetIdx); return -1; }
251
252 return 0;
253 }
254
255 /************************************************************************/
256 /* */
257 /* Find encodings that are needed for a font. */
258 /* */
259 /* 1) Find the legacy encodings that intersect the collection of */
260 /* characters that the document uses in this font. Also find the */
261 /* charset that has the highest number of characters. */
262 /* 2) Ignore the best character set and always use ANSI as the first */
263 /* character set to use. */
264 /* 3) Add the remaining legacy encodings to the set of fonts. The */
265 /* ones with the highest number of characters in the font have */
266 /* priority. */
267 /* 4) Remember the biggest charset that has a particular unicode. */
268 /* this administration is used to switch while saving the document.*/
269 /* */
270 /************************************************************************/
271
docFontFindLegacyEncodings(DocumentFont * df)272 int docFontFindLegacyEncodings( DocumentFont * df )
273 {
274 int rval= 0;
275
276 int csIdx;
277
278 unsigned char isUsed[CHARSETidx_COUNT];
279 int hitCount[CHARSETidx_COUNT];
280 int hitsLeft[CHARSETidx_COUNT];
281 IndexSet legacyUsed[CHARSETidx_COUNT];
282
283 IndexSet isBest;
284
285 int bestCount;
286 int bestIndex;
287
288 df->dfCharsetIdxUsedCount= 0;
289
290 utilInitIndexSet( &isBest );
291
292 for ( csIdx= 0; csIdx < CHARSETidx_COUNT; csIdx++ )
293 {
294 utilInitIndexSet( &(legacyUsed[csIdx]) );
295 hitCount[csIdx]= 0;
296 hitsLeft[csIdx]= 0;
297 isUsed[csIdx]= 0;
298 df->dfCharsetIdxUsed[csIdx]= -1;
299 }
300
301 if ( ! strcmp( df->dfName, "ITC Zapf Dingbats" ) ||
302 ! strcmp( df->dfName, "Symbol" ) )
303 { goto superfluous; }
304
305 /* 1 */
306 bestCount= 0; bestIndex= -1;
307 for ( csIdx= 0; csIdx < CHARSETidx_COUNT; csIdx++ )
308 {
309 const IndexSet * legacySet;
310
311 legacySet= utilOfficeCharsetGetCodeSet( csIdx );
312 if ( ! legacySet )
313 { continue; }
314
315 hitCount[csIdx]= utilIndexSetIntersect( &(legacyUsed[csIdx]),
316 &(df->dfUnicodesUsed), legacySet );
317 if ( hitCount[csIdx] < 0 )
318 { LLDEB(csIdx,hitCount[csIdx]); rval= -1; goto ready; }
319 hitsLeft[csIdx]= hitCount[csIdx];
320
321 if ( bestCount < hitsLeft[csIdx] )
322 {
323 bestCount= hitsLeft[csIdx];
324 bestIndex= csIdx;
325 }
326 }
327
328 /* 2 */
329 if ( bestIndex > 0 )
330 {
331 int ansiCount= utilIndexSetRemoveAll( &isBest, &(legacyUsed[0]),
332 &(legacyUsed[bestIndex]) );
333 if ( ansiCount > 0 )
334 { bestIndex= 0; }
335 }
336
337 /* 3 */
338 while( bestIndex >= 0 )
339 {
340 const IndexSet * subtract= &(legacyUsed[bestIndex]);
341
342 df->dfCharsetIdxUsed[df->dfCharsetIdxUsedCount]= bestIndex;
343 df->dfCharsetIdxUsedCount++;
344 isUsed[bestIndex]= 1;
345
346 bestCount= 0; bestIndex= -1;
347 for ( csIdx= 0; csIdx < CHARSETidx_COUNT; csIdx++ )
348 {
349 if ( isUsed[csIdx] || hitsLeft[csIdx] == 0 )
350 { continue; }
351
352 hitsLeft[csIdx]= utilIndexSetRemoveAll( &(legacyUsed[csIdx]),
353 &(legacyUsed[csIdx]), subtract );
354 if ( hitsLeft[csIdx] < 0 )
355 { LLDEB(csIdx,hitsLeft[csIdx]); rval= -1; goto ready; }
356
357 if ( bestCount < hitsLeft[csIdx] )
358 {
359 bestCount= hitsLeft[csIdx];
360 bestIndex= csIdx;
361 }
362 }
363 }
364
365 /* 4 */
366 bestIndex= df->dfCharsetIdxUsedCount- 1;
367 while( bestIndex >= 0 )
368 {
369 FontCharset fc;
370
371 fc.fcFont= df;
372 fc.fcCharsetIdx= df->dfCharsetIdxUsed[bestIndex];
373
374 if ( utilIndexSetForAll( &(legacyUsed[fc.fcCharsetIdx]),
375 docFontSetUnicodeCharsetIdx, (void *)&fc ) < 0 )
376 { LDEB(fc.fcCharsetIdx); rval= -1; goto ready; }
377
378 bestIndex--;
379 }
380
381 superfluous:
382
383 /* Nothing found.. Take FONTcharsetDEFAULT */
384 if ( utilIndexSetGetNext( &(df->dfUnicodesUsed), -1 ) >= 0 &&
385 df->dfCharsetIdxUsedCount == 0 )
386 {
387 if ( ! utilGetOfficeCharsetByCharset( &(df->dfCharsetIdxUsed[0]),
388 FONTcharsetDEFAULT ) )
389 { LDEB(1); }
390
391 df->dfCharsetIdxUsedCount++;
392 }
393
394 ready:
395
396 utilCleanIndexSet( &isBest );
397
398 for ( csIdx= 0; csIdx < CHARSETidx_COUNT; csIdx++ )
399 { utilCleanIndexSet( &(legacyUsed[csIdx]) ); }
400
401 return rval;
402 }
403