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