xref: /plan9/sys/src/cmd/aux/antiword/fonts_u.c (revision 25b329d522281a8cdd35da0dcc08c3fc621059a9)
1 /*
2  * fonts_u.c
3  * Copyright (C) 1999-2004 A.J. van Os; Released under GNU GPL
4  *
5  * Description:
6  * Functions to deal with fonts (Unix version)
7  */
8 
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include "antiword.h"
13 #include "fontinfo.h"
14 
15 /* Don't use fonts, just plain text */
16 static BOOL		bUsePlainText = TRUE;
17 /* Which character set should be used */
18 static encoding_type	eEncoding = encoding_neutral;
19 
20 
21 /*
22  * pOpenFontTableFile - open the Font translation file
23  *
24  * Returns the file pointer or NULL
25  */
26 FILE *
pOpenFontTableFile(void)27 pOpenFontTableFile(void)
28 {
29 	FILE		*pFile;
30 	const char	*szHome, *szAntiword, *szGlobalFile;
31 	char		szEnvironmentFile[PATH_MAX+1];
32 	char		szLocalFile[PATH_MAX+1];
33 
34 	szEnvironmentFile[0] = '\0';
35 	szLocalFile[0] = '\0';
36 
37 	/* Try the environment version of the fontnames file */
38 	szAntiword = szGetAntiwordDirectory();
39 	if (szAntiword != NULL && szAntiword[0] != '\0') {
40 		if (strlen(szAntiword) +
41 		    sizeof(FILE_SEPARATOR FONTNAMES_FILE) >=
42 		    sizeof(szEnvironmentFile)) {
43 			werr(0,
44 			"The name of your ANTIWORDHOME directory is too long");
45 			return NULL;
46 		}
47 		sprintf(szEnvironmentFile, "%s%s",
48 			szAntiword,
49 			FILE_SEPARATOR FONTNAMES_FILE);
50 		DBG_MSG(szEnvironmentFile);
51 
52 		pFile = fopen(szEnvironmentFile, "r");
53 		if (pFile != NULL) {
54 			return pFile;
55 		}
56 	}
57 
58 	/* Try the local version of the fontnames file */
59 	szHome = szGetHomeDirectory();
60 	if (strlen(szHome) +
61 	    sizeof(FILE_SEPARATOR ANTIWORD_DIR FILE_SEPARATOR FONTNAMES_FILE) >=
62 	    sizeof(szLocalFile)) {
63 		werr(0, "The name of your HOME directory is too long");
64 		return NULL;
65 	}
66 
67 	sprintf(szLocalFile, "%s%s",
68 		szHome,
69 		FILE_SEPARATOR ANTIWORD_DIR FILE_SEPARATOR FONTNAMES_FILE);
70 	DBG_MSG(szLocalFile);
71 
72 	pFile = fopen(szLocalFile, "r");
73 	if (pFile != NULL) {
74 		return pFile;
75 	}
76 
77 	/* Try the global version of the fontnames file */
78 	szGlobalFile = GLOBAL_ANTIWORD_DIR FILE_SEPARATOR FONTNAMES_FILE;
79 	DBG_MSG(szGlobalFile);
80 
81 	pFile = fopen(szGlobalFile, "r");
82 	if (pFile != NULL) {
83 		return pFile;
84 	}
85 
86 	if (szEnvironmentFile[0] != '\0') {
87 		werr(0, "I can not open your fontnames file.\n"
88 			"Neither '%s' nor\n"
89 			"'%s' nor\n"
90 			"'%s' can be opened for reading.",
91 			szEnvironmentFile, szLocalFile, szGlobalFile);
92 	} else {
93 		werr(0, "I can not open your fontnames file.\n"
94 			"Neither '%s' nor\n"
95 			"'%s' can be opened for reading.",
96 			szLocalFile, szGlobalFile);
97 	}
98 	return NULL;
99 } /* end of pOpenFontTableFile */
100 
101 /*
102  * vCloseFont - close the current font, if any
103  */
104 void
vCloseFont(void)105 vCloseFont(void)
106 {
107 	NO_DBG_MSG("vCloseFont");
108 	/* For safety: to be overwritten at the next call of tOpenfont() */
109 	eEncoding = encoding_neutral;
110 	bUsePlainText = TRUE;
111 } /* end of vCloseFont */
112 
113 /*
114  * tOpenFont - make the specified font the current font
115  *
116  * Returns the font reference number
117  */
118 drawfile_fontref
tOpenFont(UCHAR ucWordFontNumber,USHORT usFontStyle,USHORT usWordFontSize)119 tOpenFont(UCHAR ucWordFontNumber, USHORT usFontStyle, USHORT usWordFontSize)
120 {
121 	options_type	tOptions;
122 	const char	*szOurFontname;
123 	size_t	tIndex;
124 	int	iFontnumber;
125 
126 	NO_DBG_MSG("tOpenFont");
127 	NO_DBG_DEC(ucWordFontNumber);
128 	NO_DBG_HEX(usFontStyle);
129 	NO_DBG_DEC(usWordFontSize);
130 
131 	/* Keep the relevant bits */
132 	usFontStyle &= FONT_BOLD|FONT_ITALIC;
133 	NO_DBG_HEX(usFontStyle);
134 
135 	vGetOptions(&tOptions);
136 	eEncoding = tOptions.eEncoding;
137 	bUsePlainText = tOptions.eConversionType != conversion_draw &&
138 			tOptions.eConversionType != conversion_ps &&
139 			tOptions.eConversionType != conversion_pdf;
140 
141 	if (bUsePlainText) {
142 		/* Plain text, no fonts */
143 		return (drawfile_fontref)0;
144 	}
145 
146 	iFontnumber = iGetFontByNumber(ucWordFontNumber, usFontStyle);
147 	szOurFontname = szGetOurFontname(iFontnumber);
148 	if (szOurFontname == NULL || szOurFontname[0] == '\0') {
149 		DBG_DEC(iFontnumber);
150 		return (drawfile_fontref)0;
151 	}
152 	NO_DBG_MSG(szOurFontname);
153 
154 	for (tIndex = 0; tIndex < elementsof(szFontnames); tIndex++) {
155 		if (STREQ(szFontnames[tIndex], szOurFontname)) {
156 			NO_DBG_DEC(tIndex);
157 			return (drawfile_fontref)tIndex;
158 		}
159 	}
160 	return (drawfile_fontref)0;
161 } /* end of tOpenFont */
162 
163 /*
164  * tOpenTableFont - make the table font the current font
165  *
166  * Returns the font reference number
167  */
168 drawfile_fontref
tOpenTableFont(USHORT usWordFontSize)169 tOpenTableFont(USHORT usWordFontSize)
170 {
171 	options_type	tOptions;
172 	int	iWordFontnumber;
173 
174 	NO_DBG_MSG("tOpenTableFont");
175 
176 	vGetOptions(&tOptions);
177 	eEncoding = tOptions.eEncoding;
178 	bUsePlainText = tOptions.eConversionType != conversion_draw &&
179 			tOptions.eConversionType != conversion_ps &&
180 			tOptions.eConversionType != conversion_pdf;
181 
182 	if (bUsePlainText) {
183 		/* Plain text, no fonts */
184 		return (drawfile_fontref)0;
185 	}
186 
187 	iWordFontnumber = iFontname2Fontnumber(TABLE_FONT, FONT_REGULAR);
188 	if (iWordFontnumber < 0 || iWordFontnumber > (int)UCHAR_MAX) {
189 		DBG_DEC(iWordFontnumber);
190 		return (drawfile_fontref)0;
191 	}
192 
193 	return tOpenFont((UCHAR)iWordFontnumber, FONT_REGULAR, usWordFontSize);
194 } /* end of tOpenTableFont */
195 
196 /*
197  * szGetFontname - get the fontname
198  */
199 const char *
szGetFontname(drawfile_fontref tFontRef)200 szGetFontname(drawfile_fontref tFontRef)
201 {
202 	fail((size_t)(UCHAR)tFontRef >= elementsof(szFontnames));
203 	return szFontnames[(int)(UCHAR)tFontRef];
204 } /* end of szGetFontname */
205 
206 /*
207  * lComputeStringWidth - compute the string width
208  *
209  * Note: the fontsize is specified in half-points!
210  *       the stringlength is specified in bytes, not characters!
211  *
212  * Returns the string width in millipoints
213  */
214 long
lComputeStringWidth(const char * szString,size_t tStringLength,drawfile_fontref tFontRef,USHORT usFontSize)215 lComputeStringWidth(const char *szString, size_t tStringLength,
216 	drawfile_fontref tFontRef, USHORT usFontSize)
217 {
218 	USHORT	*ausCharWidths;
219 	UCHAR	*pucChar;
220 	long	lRelWidth;
221 	size_t	tIndex;
222 	int	iFontRef;
223 
224 	fail(szString == NULL);
225 	fail(usFontSize < MIN_FONT_SIZE || usFontSize > MAX_FONT_SIZE);
226 
227 	if (szString[0] == '\0' || tStringLength == 0) {
228 		/* Empty string */
229 		return 0;
230 	}
231 
232 	if (eEncoding == encoding_utf_8) {
233 		fail(!bUsePlainText);
234 		return lChar2MilliPoints(
235 			utf8_strwidth(szString, tStringLength));
236 	}
237 
238 	if (bUsePlainText) {
239 		/* No current font, use "systemfont" */
240 		return lChar2MilliPoints(tStringLength);
241 	}
242 
243 	if (eEncoding == encoding_cyrillic) {
244 		/* FIXME: until the character tables are available */
245 		return (tStringLength * 600L * (long)usFontSize + 1) / 2;
246 	}
247 
248 	DBG_DEC_C(eEncoding != encoding_latin_1 &&
249 		eEncoding != encoding_latin_2, eEncoding);
250 	fail(eEncoding != encoding_latin_1 &&
251 		eEncoding != encoding_latin_2);
252 
253 	/* Compute the relative string width */
254 	iFontRef = (int)(UCHAR)tFontRef;
255 	if (eEncoding == encoding_latin_2) {
256 		ausCharWidths = ausCharacterWidths2[iFontRef];
257 	} else {
258 		ausCharWidths = ausCharacterWidths1[iFontRef];
259 	}
260 	lRelWidth = 0;
261 	for (tIndex = 0, pucChar = (UCHAR *)szString;
262 	     tIndex < tStringLength;
263 	     tIndex++, pucChar++) {
264 		lRelWidth += (long)ausCharWidths[(int)*pucChar];
265 	}
266 
267 	/* Compute the absolute string width */
268 	return (lRelWidth * (long)usFontSize + 1) / 2;
269 } /* end of lComputeStringWidth */
270 
271 /*
272  * tCountColumns - count the number of columns in a string
273  *
274  * Note: the length is specified in bytes!
275  *       A UTF-8 a character can be 0, 1 or 2 columns wide.
276  *
277  * Returns the number of columns
278  */
279 size_t
tCountColumns(const char * szString,size_t tLength)280 tCountColumns(const char *szString, size_t tLength)
281 {
282 	fail(szString == NULL);
283 
284 	if (eEncoding != encoding_utf_8) {
285 		/* One byte, one character, one column */
286 		return tLength;
287 	}
288 	return (size_t)utf8_strwidth(szString, tLength);
289 } /* end of tCountColumns */
290 
291 /*
292  * tGetCharacterLength - the length of the specified character in bytes
293  *
294  * Returns the length in bytes
295  */
296 size_t
tGetCharacterLength(const char * szString)297 tGetCharacterLength(const char *szString)
298 {
299 	fail(szString == NULL);
300 
301 	if (eEncoding != encoding_utf_8) {
302 		return 1;
303 	}
304 	return (size_t)utf8_chrlength(szString);
305 } /* end of tGetCharacterLength */
306