1 /***************************************************************************
2  * font.cpp is part of Math Graphic Library
3  * Copyright (C) 2007-2016 Alexey Balakin <mathgl.abalakin@gmail.ru>       *
4  *                                                                         *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU Lesser General Public License  as       *
7  *   published by the Free Software Foundation; either version 3 of the    *
8  *   License, or (at your option) any later version.                       *
9  *                                                                         *
10  *   This program is distributed in the hope that it will be useful,       *
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13  *   GNU General Public License for more details.                          *
14  *                                                                         *
15  *   You should have received a copy of the GNU Lesser General Public     *
16  *   License along with this program; if not, write to the                 *
17  *   Free Software Foundation, Inc.,                                       *
18  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
19  ***************************************************************************/
20 #include <locale.h>
21 #include <ctype.h>
22 #include <wctype.h>
23 #ifdef WIN32
24 #include <io.h>
25 #include <direct.h>
26 #else
27 #include <unistd.h>
28 #endif
29 
30 #if !defined(__BORLANDC__) || (__CODEGEARC__ >=  0x0630)
31 #include <algorithm>
32 #else
33 #include <algorithm.h>
34 #endif
35 
36 #include "mgl2/base.h"
37 #include "mgl2/font.h"
38 #include "def_font.cc"
39 #include "tex_table.cc"
40 //-----------------------------------------------------------------------------
41 //mglFont mglDefFont("nofont");
42 #define MGL_USE_H12	{if(h1<y1) y1=h1;	if(h2>y2) y2=h2;	h1=1e5;	h2=-1e5;}
43 //-----------------------------------------------------------------------------
44 mglFont *mglDefFont=NULL;
45 //-----------------------------------------------------------------------------
mgl_wcslen(const wchar_t * str)46 size_t MGL_EXPORT_PURE mgl_wcslen(const wchar_t *str)
47 {
48 	long i=0;
49 	if(str)	while(str[i])	i++;
50 	return i;
51 }
52 //-----------------------------------------------------------------------------
mgl_internal_code(unsigned s,const std::vector<mglGlyphDescr> & glyphs)53 long MGL_EXPORT_PURE mgl_internal_code(unsigned s, const std::vector<mglGlyphDescr> &glyphs)
54 {
55 	long i1=0,i2=glyphs.size()-1;
56 	wchar_t j = wchar_t(s & MGL_FONT_MASK);
57 	// let suppose that id[i]<id[i+1]
58 	while(i1<i2)
59 	{
60 		long i = (i1+i2)/2;
61 		if(j<glyphs[i].id)		i2 = i;
62 		else if(j>glyphs[i].id)	i1=i+1;
63 		else return i;
64 	}
65 	return j==glyphs[i2].id ? i2 : -1;
66 }
67 //-----------------------------------------------------------------------------
mglGetStyle(const char * how,int * font,int * align)68 bool MGL_EXPORT mglGetStyle(const char *how, int *font, int *align)
69 {
70 	bool col=false;
71 	if(align)	*align = 1;	// centering text by default
72 	if(!how || *how==0)	return col;
73 	// NOTE: no brightness for text color
74 	for(;*how && *how!=':';how++)
75 	{
76 		if(strchr(MGL_COLORS,*how))		col = true;
77 		if(*how=='{' && how[1]=='x')	col = true;
78 	}
79 	if(align)
80 	{
81 		*align = 1;
82 		if(strchr(how,'R'))	*align = 2;
83 //		if(strchr(how,'C'))	*align = 1;
84 		if(strchr(how,'L'))	*align = 0;
85 		if(strchr(how,'D'))	*align+= 4;
86 	}
87 	if(font)
88 	{
89 		*font = 0;
90 		if(strchr(how,'b'))	*font = *font|MGL_FONT_BOLD;
91 		if(strchr(how,'i'))	*font = *font|MGL_FONT_ITAL;
92 		if(strchr(how,'w'))	*font = *font|MGL_FONT_WIRE;
93 		if(strchr(how,'o'))	*font = *font|MGL_FONT_OLINE;
94 		if(strchr(how,'u'))	*font = *font|MGL_FONT_ULINE;
95 	}
96 	return col;
97 }
98 //-----------------------------------------------------------------------------
Puts(const char * str,const char * how,float c1,float c2) const99 float mglFont::Puts(const char *str,const char *how,float c1,float c2) const
100 {
101 	int font=0, align=1;	float w=0;
102 	mglGetStyle(how,&font,&align);
103 	MGL_TO_WCS(str,w = Puts(wcs,font,align,c1,c2));
104 	return w;
105 }
106 //-----------------------------------------------------------------------------
Width(const char * str,const char * how,float * y1,float * y2) const107 float mglFont::Width(const char *str,const char *how, float *y1, float *y2) const
108 {
109 	float w=0;
110 	MGL_TO_WCS(str,w = Width(wcs,how,y1,y2));
111 	return w;
112 }
113 //-----------------------------------------------------------------------------
Puts(const wchar_t * str,const char * how,float c1,float c2) const114 float mglFont::Puts(const wchar_t *str,const char *how,float c1,float c2) const
115 {
116 	int font=0, align=1;
117 	mglGetStyle(how,&font,&align);
118 	return Puts(str, font, align,c1,c2);
119 }
120 //-----------------------------------------------------------------------------
Width(const wchar_t * str,const char * how,float * y1,float * y2) const121 float mglFont::Width(const wchar_t *str,const char *how, float *y1, float *y2) const
122 {
123 	int font=0, align=1;
124 	float v1,v2;
125 	if(!y1)	y1 = &v1;
126 	if(!y2)	y2 = &v2;
127 	mglGetStyle(how,&font,&align);
128 	return Width(str, font, align, *y1, *y2);
129 }
130 //-----------------------------------------------------------------------------
Puts(const wchar_t * str,int font,int align,float c1,float c2) const131 float mglFont::Puts(const wchar_t *str,int font,int align, float c1,float c2) const
132 {
133 	if(GetNumGlyph()==0 || !str || *str==0)	return 0;
134 	float ww=0,w=0,h = (align&4) ? 500./fact[0] : 0, y1=0,y2=0;
135 	size_t size = mgl_wcslen(str)+1,num=0;
136 	if(parse)
137 	{
138 		unsigned *wcs = new unsigned[size], *buf=wcs;
139 		memcpy(wcs,str,size*sizeof(wchar_t));
140 		Convert(str, wcs);
141 		for(size_t i=0;wcs[i];i++)
142 		{
143 			if(wcs[i]=='\n')	// parse '\n' symbol
144 			{
145 				wcs[i]=0;	w = Puts(buf,0,0,1.f,0x10|font,c1,c2, y1,y2);	// find width
146 				Puts(buf,-w*(align&3)/2.f,-h - 660*num/fact[0],1.f,font,c1,c2, y1,y2);	// draw it really
147 				buf=wcs+i+1;	num++;	if(w>ww)	ww=w;
148 			}
149 // 			if(wcs[i]=='\\' && wcs[i+1]=='n' && (wcs[i+2]>' ' || wcschr(L"{}[]()!@#$%^&*/-?.,_=+\\\"", wcs[i+2])))	// parse '\n' symbol
150 // 			{
151 // 				wcs[i]=0;	w = Puts(buf,0,0,1.f,0x10|font,c1,c2);	// find width
152 // 				Puts(buf,-w*(align&3)/2.f,-h - 720.*num/fact[0],1.f,font,c1,c2);	// draw it really
153 // 				buf=wcs+i+2;	num++;	if(w>ww)	ww=w;
154 // 			}
155 		}
156 		// draw string itself
157 		w = Puts(buf,0,0,1.f,0x10|font,c1,c2, y1,y2);	// find width
158 		Puts(buf,-w*(align&3)/2.f,-h - 660*num/fact[0],1.f,font,c1,c2, y1,y2);	// draw it really
159 		if(w>ww)	ww=w;
160 		delete []wcs;
161 	}
162 	else
163 	{
164 		int s = (font/MGL_FONT_BOLD)&3;
165 		h *= fact[0]/fact[s];
166 		for(size_t i=0;i<size;i++)		// find width
167 		{
168 			long j = str[i]!=' ' ? Internal(str[i]) : Internal('!');
169 			if(j==-1)	continue;
170 			w+= GetWidth(s,j)/fact[s];
171 		}
172 		ww = w;		w *= -(align&3)/2.f;
173 		if(gr)	for(size_t i=0;i<size;i++)		// draw it
174 		{
175 			long j=0;	//Internal('!');
176 			if(str[i]!=' ')
177 			{
178 				j = Internal(str[i]);
179 				if(j==-1)	continue;
180 				gr->Glyph(w, -h, 1, (s+(font&MGL_FONT_WIRE))?4:0, j, c1+i*(c2-c1)/(size-1));
181 			}
182 			w+= GetWidth(s,j)/fact[s];
183 		}
184 	}
185 	return ww;
186 }
187 //-----------------------------------------------------------------------------
Width(const wchar_t * str,int font,int align,float & y1,float & y2) const188 float mglFont::Width(const wchar_t *str,int font, int align, float &y1, float &y2) const
189 {
190 	if(GetNumGlyph()==0 || !str || *str==0)	return 0;
191 	float ww=0,w=0, h1=1e5,h2=-1e5;
192 	float h = (align&4) ? 500./fact[0] : 0;
193 	size_t size = mgl_wcslen(str)+1, num=0;
194 	y1=1e5;	y2=-1e5;
195 	if(parse)
196 	{
197 		unsigned *wcs = new unsigned[size], *buf=wcs;
198 		memcpy(wcs,str,size*sizeof(wchar_t));
199 		Convert(str, wcs);
200 		for(size_t i=0;wcs[i];i++)	if(wcs[i]=='\n')	// parse '\n' symbol
201 		{
202 			wcs[i]=0;	w = Puts(buf,0,0,1.,0x10|font,'k','k', h1,h2);	// find width
203 			h1 -= h+660*num/fact[0];	h2 -= h+660*num/fact[0];
204 			MGL_USE_H12
205 			buf=wcs+i+1;	if(w>ww)	ww=w;	num++;
206 		}
207 		w = Puts(buf,0,0,1.,0x10|font,'k','k', h1,h2);
208 		h1 -= h+660*num/fact[0];	h2 -= h+660*num/fact[0];
209 		MGL_USE_H12
210 		if(w<ww)	w=ww;
211 		delete []wcs;
212 	}
213 	else
214 	{
215 		int s = (font/MGL_FONT_BOLD)&3;
216 		for(size_t i=0;i<size;i++)
217 		{
218 			long j = str[i]!=' ' ? Internal(str[i]) : Internal('!');
219 			if(j==-1)	continue;
220 			w+= GetWidth(s,j)/fact[s];
221 			h1 = glyphs[j].y1[s]/fact[s];	h2 = glyphs[j].y2[s]/fact[s];
222 			MGL_USE_H12
223 		}
224 	}
225 	return w;
226 }
227 //-----------------------------------------------------------------------------
Height(int font) const228 float mglFont::Height(int font) const
229 {
230 	if(GetNumGlyph()==0)	return 0;
231 	int s = (font/MGL_FONT_BOLD)&3;
232 	return Hscale*660/fact[s];
233 }
234 //-----------------------------------------------------------------------------
Height(const char * how) const235 float mglFont::Height(const char *how) const
236 {
237 	if(GetNumGlyph()==0)	return 0;
238 	int s=0;
239 	if(how)
240 	{
241 		if(strchr(how,'b'))	s = s|1;
242 		if(strchr(how,'i'))	s = s|2;
243 	}
244 	return Hscale*660/fact[s];
245 }
246 //-----------------------------------------------------------------------------
247 /// Table of acents and its UTF8 codes
248 MGL_NO_EXPORT mglTeXsymb mgl_act_symb[] = {
249 	{0x02c6, L"hat"}, {0x02dc, L"tilde"}, {0x02d9, L"dot"}, {0x00a8, L"ddot"}, {0x20db, L"dddot"}, {0x20dc, L"ddddot"}, {0x02ca, L"acute"}, {0x02c7, L"check"}, {0x02cb, L"grave"}, {0x20d7, L"vec"}, {0x02c9, L"bar"}, {0x02d8, L"breve"},
250 	/*end*/{0, L"\0"}};
251 //-----------------------------------------------------------------------------
mgl_tex_symb_cmp(const void * a,const void * b)252 int MGL_LOCAL_PURE mgl_tex_symb_cmp(const void *a, const void *b)
253 {
254 	const mglTeXsymb *aa = (const mglTeXsymb *)a;
255 	const mglTeXsymb *bb = (const mglTeXsymb *)b;
256 	return wcscmp(aa->tex, bb->tex);
257 }
258 //-----------------------------------------------------------------------------
259 // parse LaTeX commands (mostly symbols and acents, and some font-style commands)
Parse(const wchar_t * s) const260 unsigned mglFont::Parse(const wchar_t *s) const
261 {
262 	unsigned res = unsigned(-2);		// Default is no symbol
263 	if(!s || !s[0])	return res;
264 	mglTeXsymb tst, *rts;
265 	tst.tex = s;
266 	rts = (mglTeXsymb *) bsearch(&tst, mgl_tex_symb, mgl_tex_num, sizeof(mglTeXsymb), mgl_tex_symb_cmp);
267 	if(rts)	return rts->kod;
268 
269 	for(long k=0;mgl_act_symb[k].kod;k++)	// acents
270 		if(!wcscmp(s,mgl_act_symb[k].tex))
271 			return mgl_act_symb[k].kod | MGL_FONT_ZEROW;
272 	// arbitrary UTF symbol
273 	if(s[0]=='u' && s[1]=='t' && s[2]=='f')
274 	{	long k = wcstoul(s+3,NULL,16);	return wchar_t(k);	}
275 	// font/style changes for next symbol
276 	if(!wcscmp(s,L"big"))			res = unsigned(-5);
277 	else if(!wcscmp(s,L"frac"))		res = unsigned(-6);
278 	else if(!wcscmp(s,L"stack"))	res = unsigned(-7);
279 	else if(!wcscmp(s,L"overset"))	res = unsigned(-8);
280 	else if(!wcscmp(s,L"underset"))	res = unsigned(-9);
281 	else if(!wcscmp(s,L"stackr"))	res = unsigned(-10);
282 	else if(!wcscmp(s,L"stackl"))	res = unsigned(-11);
283 	else if(!wcscmp(s,L"sub"))		res = unsigned(-9);	//unsigned(-12);
284 	else if(!wcscmp(s,L"sup"))		res = unsigned(-8);	//unsigned(-13);
285 	else if(!wcscmp(s,L"textsc"))	res = unsigned(-14);	// new
286 	else if(!wcscmp(s,L"dfrac"))	res = unsigned(-15);
287 	else if(!wcscmp(s,L"b"))		res = MGL_FONT_BOLD;
288 	else if(!wcscmp(s,L"i"))		res = MGL_FONT_ITAL;
289 	else if(!wcscmp(s,L"bi"))		res = MGL_FONT_BOLD|MGL_FONT_ITAL;
290 	else if(!wcscmp(s,L"r"))		res = unsigned(-1);
291 	else if(!wcscmp(s,L"a"))		res = MGL_FONT_OLINE;
292 	else if(!wcscmp(s,L"u"))		res = MGL_FONT_ULINE;
293 	else if(!wcscmp(s,L"n"))		res = '\n';
294 	else if(!wcscmp(s,L"overline"))	res = MGL_FONT_OLINE;
295 	else if(!wcscmp(s,L"underline"))res = MGL_FONT_ULINE;
296 	else if(!wcscmp(s,L"textbf"))	res = MGL_FONT_BOLD;
297 	else if(!wcscmp(s,L"textit"))	res = MGL_FONT_ITAL;
298 	else if(!wcscmp(s,L"textrm"))	res = unsigned(-1);
299 	else if(!wcscmp(s,L"T2A"))		res = unsigned(-1);
300 	else if(!wcscmp(s,L"w"))		res = MGL_FONT_WIRE;
301 	else if(!wcscmp(s,L"wire"))		res = MGL_FONT_WIRE;
302 	else if(!wcsncmp(s,L"color",5))	res = MGL_COLOR_MASK + (0xff & s[5]);
303 	return res;
304 }
305 //-----------------------------------------------------------------------------
Convert(const wchar_t * str,unsigned * res) const306 void mglFont::Convert(const wchar_t *str, unsigned *res) const
307 {
308 	size_t j=0;
309 	wchar_t s[128]=L"";		// TeX command and current char
310 	for(size_t i=0;str[i];i++)
311 	{
312 		wchar_t ch = str[i];
313 		if(ch=='\\')	// It can be TeX command
314 		{
315 			if(wcschr(L"{}_^\\@# ",str[i+1]))	// No, it is usual symbol
316 				res[j++] = str[++i];
317 			else		// Yes, it is TeX command
318 			{
319 				size_t i0=i+1, k;
320 				for(k=0;isalnum(str[++i]) && k<127;k++)	s[k] = str[i];
321 				s[k] = 0;
322 				size_t r = Parse(s);
323 				if(r==unsigned(-2))			// command not found, so use next symbol itself
324 				{	res[j++] = str[i0];	i = i0;	}
325 				else if(r)
326 				{
327 					res[j++] = r;
328 					if(str[i]>' ')	i--;
329 					if(str[i]==0)	break;
330 				}
331 			}
332 		}
333 		else if(ch=='-' && str[i+1]=='-')	{	res[j++] = 0x2212;	i++;	}
334 		else if(ch=='\b'){}
335 		else if(ch<=' ' && ch!='\n')	res[j++] = ' ';	// no \t at this moment :(
336 		else if(ch=='_')	res[j++] = MGL_FONT_LOWER;
337 		else if(ch=='^')	res[j++] = MGL_FONT_UPPER;
338 		else if(ch=='@')	res[j++] = MGL_FONT_UPPER|MGL_FONT_LOWER;
339 		else if(ch=='{')	res[j++] = unsigned(-3);
340 		else if(ch=='}')	res[j++] = unsigned(-4);
341 		else if(ch=='#' && str[i+1]>' ')
342 			res[j++] = MGL_COLOR_MASK + (0xff & str[++i]);	// TODO inline colors -- stack of RGBA colors + index
343 		else	res[j++] = ch;				// It is just symbol
344 	}
345 	res[j] = 0;
346 }
347 //-----------------------------------------------------------------------------
get_ptr(long & i,unsigned * str,unsigned ** b1,unsigned ** b2,float & w1,float & w2,float f1,float f2,int st) const348 float mglFont::get_ptr(long &i,unsigned *str, unsigned **b1, unsigned **b2,float &w1,float &w2, float f1, float f2, int st) const
349 {
350 	static unsigned s1[2]={0,0}, s2[2]={0,0};
351 	i++;
352 	if(str[i]==unsigned(-3))
353 	{
354 		i++;	*b1 = str+i;
355 		for(long k=1;k>0 && str[i];i++)
356 		{
357 			if(str[i]==unsigned(-4))	k--;
358 			if(str[i]==unsigned(-3))	k++;
359 		}
360 		str[i-1]=0;
361 	}
362 	else	{	s1[0] = str[i];	*b1 = s1;	i++;	}
363 	if(str[i]==unsigned(-3))
364 	{
365 		i++;	*b2 = str+i;
366 		for(long k=1;k>0 && str[i];i++)
367 		{
368 			if(str[i]==unsigned(-4))	k--;
369 			if(str[i]==unsigned(-3))	k++;
370 		}
371 		str[i-1]=0;
372 	}
373 	else	{	s2[0] = str[i];	*b2 = s2;	i++;	}
374 	i--;
375 	float y1=0,y2=0;
376 	w1 = Puts(*b1, 0, 0, f1, 0x10|st,'k','k', y1,y2);
377 	w2 = Puts(*b2, 0, 0, f2, 0x10|st,'k','k', y1,y2);
378 	return w1>w2 ? w1 : w2;
379 }
380 //-----------------------------------------------------------------------------
draw_ouline(int st,float x,float y,float f,float g,float ww,float ccol) const381 void mglFont::draw_ouline(int st, float x, float y, float f, float g, float ww, float ccol) const
382 {
383 	if(st&MGL_FONT_OLINE)
384 		gr->Glyph(x,y+499*f/g, ww*g, (st&MGL_FONT_WIRE)?12:8, 0, ccol);
385 	if(st&MGL_FONT_ULINE)
386 		gr->Glyph(x,y-200*f/g, ww*g, (st&MGL_FONT_WIRE)?12:8, 0, ccol);
387 }
388 //-----------------------------------------------------------------------------
389 #define MGL_CLEAR_STYLE {st = style;	yy = y;	ff = f;	ccol=c1+dc*i;	a = (st/MGL_FONT_BOLD)&3;}
Puts(const unsigned * text,float x,float y,float f,int style,float c1,float c2,float & y1,float & y2) const390 float mglFont::Puts(const unsigned *text, float x,float y,float f,int style,float c1,float c2, float &y1,float &y2) const
391 {
392 	if(GetNumGlyph()==0)	return 0;
393 	float w=0;				// string width
394 	int st = style;			// current style
395 	unsigned *b1, *b2;		// pointer to substring
396 	unsigned *str;			// string itself
397 	float yy=y, ff=f, ww, w1, w2, h1=1e5,h2=-1e5;
398 	int a = (st/MGL_FONT_BOLD)&3;
399 	long i;
400 	for(i=0;text[i];i++);
401 	float dc=i>1?(c2-c1)/(i-1):0;
402 	str = new unsigned[i+1];
403 	memcpy(str,text,(i+1)*sizeof(unsigned));
404 
405 	float ccol = 0;
406 	for(long i=0;str[i];i++)
407 	{
408 		ccol = ccol<0?ccol:c1+dc*i;
409 		unsigned s = str[i];		ww = 0;
410 		if(s==unsigned(-3))	// recursion call here for {}-block
411 		{
412 			i++;	b1 = str+i;
413 			for(long k=1;k>0 && str[i];i++)
414 			{
415 				if(str[i]==unsigned(-4))	k--;
416 				if(str[i]==unsigned(-3))	k++;
417 			}
418 			str[i-1]=0;	i--;
419 			ww = Puts(b1, x, yy, ff, (st&(~MGL_FONT_OLINE)&(~MGL_FONT_ULINE)), ccol,ccol, h1,h2);
420 			MGL_USE_H12
421 			if(gr && !(style&0x10))	// add under-/over- line now
422 				draw_ouline(st,x,y,f,fact[a],ww,ccol);
423 			MGL_CLEAR_STYLE
424 		}
425 		else if(s=='\n')	// newline
426 		{
427 			ww = get_ptr(i, str, &b1, &b2, w1, w2, ff, ff, st);
428 			Puts(b1, x+(ww-w1)/2, yy, ff, (st&(~MGL_FONT_OLINE)&(~MGL_FONT_ULINE)), ccol,ccol, h1,h2);
429 			MGL_USE_H12
430 			Puts(b2, x+(ww-w2)/2, yy-660*ff/fact[a], ff, (st&(~MGL_FONT_OLINE)&(~MGL_FONT_ULINE)), ccol,ccol, h1,h2);
431 			MGL_USE_H12
432 			MGL_CLEAR_STYLE
433 		}
434 		else if(s==unsigned(-9))	// underset or sub
435 		{
436 			ww = get_ptr(i, str, &b1, &b2, w1, w2, ff, ff/4, st);
437 			Puts(b1, x+(ww-w1)/2, yy, ff, (st&(~MGL_FONT_OLINE)&(~MGL_FONT_ULINE)), ccol,ccol, h1,h2);
438 			MGL_USE_H12
439 			Puts(b2, x+(ww-w2)/2, yy-175*ff/fact[a], ff/3, (st&(~MGL_FONT_OLINE)&(~MGL_FONT_ULINE)), ccol,ccol, h1,h2);
440 			MGL_USE_H12
441 			if(gr && !(style&0x10))	// add under-/over- line now
442 				draw_ouline(st,x,y,f,fact[a],ww,ccol);
443 			MGL_CLEAR_STYLE
444 		}
445 		else if(s==unsigned(-8))	// overset or sup
446 		{
447 			ww = get_ptr(i, str, &b1, &b2, w1, w2, ff, ff/4, st);
448 			Puts(b1, x+(ww-w1)/2, yy, ff, (st&(~MGL_FONT_OLINE)&(~MGL_FONT_ULINE)), ccol,ccol, h1,h2);
449 			MGL_USE_H12
450 			Puts(b2, x+(ww-w2)/2, yy+400*ff/fact[a], ff/3, (st&(~MGL_FONT_OLINE)&(~MGL_FONT_ULINE)), ccol,ccol, h2,h2);
451 			MGL_USE_H12
452 			if(gr && !(style&0x10))	// add under-/over- line now
453 				draw_ouline(st,x,y,f,fact[a],ww,ccol);
454 			MGL_CLEAR_STYLE
455 		}
456 /*		else if(s==unsigned(-12))	// sub	// NOTE: unused because is the same as \underset now
457 		{
458 			ww = get_ptr(i, str, &b1, &b2, w1, w2, ff, ff/4, st);
459 			Puts(b1, x+(ww-w1)/2, yy, ff, (st&(~MGL_FONT_OLINE)&(~MGL_FONT_ULINE)), ccol,ccol);
460 			Puts(b2, x+(ww-w2)/2, yy-250*ff/fact[a], ff/4, (st&(~MGL_FONT_OLINE)&(~MGL_FONT_ULINE)), ccol,ccol);
461 			if(gr && !(style&0x10))	// add under-/over- line now
462 				draw_ouline(st,x,y,f,fact[a],ww,ccol);
463 			MGL_CLEAR_STYLE
464 		}*/
465 /*		else if(s==unsigned(-13))	// sup	// NOTE: unused because is the same as \overset now
466 		{
467 			ww = get_ptr(i, str, &b1, &b2, w1, w2, ff, ff/4, st);
468 			Puts(b1, x+(ww-w1)/2, yy, ff, (st&(~MGL_FONT_OLINE)&(~MGL_FONT_ULINE)), ccol,ccol);
469 			Puts(b2, x+(ww-w2)/2, yy+450*ff/fact[a], ff/4, (st&(~MGL_FONT_OLINE)&(~MGL_FONT_ULINE)), ccol,ccol);
470 			if(gr && !(style&0x10))	// add under-/over- line now
471 				draw_ouline(st,x,y,f,fact[a],ww,ccol);
472 			MGL_CLEAR_STYLE
473 		}*/
474 		else if(s==unsigned(-11))	// stackl
475 		{
476 			ww = get_ptr(i, str, &b1, &b2, w1, w2, ff*0.45, ff*0.45, st);
477 			Puts(b1, x, yy+250*ff/fact[a], ff*0.45, (st&(~MGL_FONT_OLINE)&(~MGL_FONT_ULINE)), ccol,ccol, h1,h2);
478 			MGL_USE_H12
479 			Puts(b2, x, yy-110*ff/fact[a], ff*0.45, (st&(~MGL_FONT_OLINE)&(~MGL_FONT_ULINE)), ccol,ccol, h1,h2);
480 			MGL_USE_H12
481 			if(gr && !(style&0x10))	// add under-/over- line now
482 				draw_ouline(st,x,y,f,fact[a],ww,ccol);
483 			MGL_CLEAR_STYLE
484 		}
485 		else if(s==unsigned(-10))	// stacr
486 		{
487 			ww = get_ptr(i, str, &b1, &b2, w1, w2, ff*0.45, ff*0.45, st);
488 			Puts(b1, x+(ww-w1), yy+250*ff/fact[a], ff*0.45, (st&(~MGL_FONT_OLINE)&(~MGL_FONT_ULINE)), ccol,ccol, h1,h2);
489 			MGL_USE_H12
490 			Puts(b2, x+(ww-w2), yy-110*ff/fact[a], ff*0.45, (st&(~MGL_FONT_OLINE)&(~MGL_FONT_ULINE)), ccol,ccol, h1,h2);
491 			MGL_USE_H12
492 			if(gr && !(style&0x10))	// add under-/over- line now
493 				draw_ouline(st,x,y,f,fact[a],ww,ccol);
494 			MGL_CLEAR_STYLE
495 		}
496 		else if(s==unsigned(-7))	// stack
497 		{
498 			ww = get_ptr(i, str, &b1, &b2, w1, w2, ff*0.45, ff*0.45, st);
499 			Puts(b1, x+(ww-w1)/2, yy+250*ff/fact[a], ff*0.45, (st&(~MGL_FONT_OLINE)&(~MGL_FONT_ULINE)), ccol,ccol, h1,h2);
500 			MGL_USE_H12
501 			Puts(b2, x+(ww-w2)/2, yy-110*ff/fact[a], ff*0.45, (st&(~MGL_FONT_OLINE)&(~MGL_FONT_ULINE)), ccol,ccol, h1,h2);
502 			MGL_USE_H12
503 			if(gr && !(style&0x10))	// add under-/over- line now
504 				draw_ouline(st,x,y,f,fact[a],ww,ccol);
505 			MGL_CLEAR_STYLE
506 		}
507 		else if(s==unsigned(-6))	// frac
508 		{
509 			ww = get_ptr(i, str, &b1, &b2, w1, w2, ff*0.45, ff*0.45, st);
510 			Puts(b1, x+(ww-w1)/2, yy+250*ff/fact[a], ff*0.45, (st&(~MGL_FONT_OLINE)&(~MGL_FONT_ULINE)), ccol,ccol, h1,h2);
511 			MGL_USE_H12
512 			Puts(b2, x+(ww-w2)/2, yy-60*ff/fact[a], ff*0.45, (st&(~MGL_FONT_OLINE)&(~MGL_FONT_ULINE)), ccol,ccol, h1,h2);
513 			MGL_USE_H12
514 			if(gr && !(style&0x10))	// add under-/over- line now
515 			{
516 				draw_ouline(st,x,y,f,fact[a],ww,ccol);
517 				gr->Glyph(x,y+150*f/fact[a], ww*fact[a], (st&MGL_FONT_WIRE)?12:8, 0, ccol);
518 			}
519 			MGL_CLEAR_STYLE
520 		}
521 		else if(s==unsigned(-15))	// dfrac
522 		{
523 			ww = get_ptr(i, str, &b1, &b2, w1, w2, ff, ff, st);
524 			Puts(b1, x+(ww-w1)/2, yy+315*ff/fact[a], ff, (st&(~MGL_FONT_OLINE)&(~MGL_FONT_ULINE)), ccol,ccol, h1,h2);
525 			MGL_USE_H12
526 			Puts(b2, x+(ww-w2)/2, yy-405*ff/fact[a], ff, (st&(~MGL_FONT_OLINE)&(~MGL_FONT_ULINE)), ccol,ccol, h1,h2);
527 			MGL_USE_H12
528 			if(gr && !(style&0x10))	// add under-/over- line now
529 			{
530 				draw_ouline(st,x,y,f,fact[a],ww,ccol);
531 				gr->Glyph(x,y+150*f/fact[a], ww*fact[a], (st&MGL_FONT_WIRE)?12:8, 0, ccol);
532 			}
533 			MGL_CLEAR_STYLE
534 		}
535 		else if(s==unsigned(-4))	MGL_CLEAR_STYLE	// should be never here but if I miss sth ...
536 		else if(s==unsigned(-14))	// script symbols
537 		{
538 			long k=1;
539 			if(str[i+1]==unsigned(-3))	for(long j=i+2;k>0 && str[j];j++)
540 			{
541 				if(str[j]==unsigned(-3))	k++;
542 				if(str[j]==unsigned(-4))	k--;
543 				if(iswlower(str[j]))
544 					str[j] = MGL_FONT_UPPER|MGL_FONT_LOWER|towupper(str[j]);
545 			}
546 		}
547 		else if(s==unsigned(-5))	// large symbol
548 			ff *= 1.5;
549 		else if(s==unsigned(-1))	// set normal font
550 			st = style & MGL_FONT_ROMAN;
551 		else if((s&MGL_COLOR_MASK)==MGL_COLOR_MASK)	// color specification
552 			ccol = -float(s & 0xff);	// TODO inline colors -- make textures
553 		else
554 		{
555 			unsigned ss = s&MGL_FONT_MASK;
556 			if(ss)	// draw symbol (glyph)
557 			{
558 				long j = Internal('!');
559 				float dx=0;
560 				if(ss>' ')
561 				{
562 					j = Internal(ss);
563 					if(j==-1)	continue;
564 					if(s & MGL_FONT_ZEROW)
565 					{
566 						long j=1;
567 						yy += 100*ff/fact[a];
568 						while(str[i+j]>=unsigned(-15))	j++;
569 						unsigned sn = str[i+j];
570 						if(sn<unsigned(-15) && (sn&MGL_FONT_MASK)>' ')	// specially center
571 						{
572 							long jj = Internal(sn&MGL_FONT_MASK);
573 							dx = jj<0?0:0.75*ff*(GetWidth(a,jj)-GetWidth(a,j))/fact[a];
574 							if(dx<0)	dx=0;
575 						}
576 					}
577 					h1 = yy+ff*glyphs[j].y1[a]/fact[a];	h2 = yy+ff*glyphs[j].y2[a]/fact[a];
578 					MGL_USE_H12
579 					if(gr && !(style&0x10))
580 					{
581 						if(st & MGL_FONT_WIRE)	gr->Glyph(x+dx,yy,ff,a+4,j,ccol);
582 						else					gr->Glyph(x+dx,yy,ff,a,j,ccol);
583 					}
584 				}
585 				ww = j>=0?ff*GetWidth(a,j)/fact[a]:0;
586 				if(gr && !(style&0x10))	// add under-/over- line now
587 					draw_ouline(st,x,y,f,fact[a],ww,ccol);
588 				if(s & MGL_FONT_ZEROW)	ww = 0;
589 				MGL_CLEAR_STYLE
590 			}
591 			// apply new styles
592 			if(s/MGL_FONT_BOLD)	st = st | (s & MGL_FONT_STYLE);
593 			a = (st/MGL_FONT_BOLD)&3;
594 			ss = (s/MGL_FONT_UPPER)%4;
595 			if(ss)
596 			{
597 				if(ss==1)		{	ff *=0.6;	yy += 250*ff/fact[a];	}	// =  500*0.4
598 				else if(ss==2)	{	ff *=0.6;	yy -=  130*ff/fact[a];	}	// = -500*0.16
599 				else if(ss==3)	{	ff *=0.6;	yy +=  60*ff/fact[a];	}	// =  500*0.12
600 			}
601 		}
602 		x += ww;	w += ww;
603 	}
604 	delete []str;
605 	return w;
606 }
607 //-----------------------------------------------------------------------------
608 // copy normal style as default for other styles
main_copy()609 void mglFont::main_copy()
610 {
611 #pragma omp parallel for
612 	for(long i=0;i<long(glyphs.size());i++)
613 	{
614 		mglGlyphDescr &g = glyphs[i];
615 		g.numl[1] = g.numl[2] = g.numl[3] = g.numl[0];
616 		g.numt[1] = g.numt[2] = g.numt[3] = g.numt[0];
617 		g.ln[1] = g.ln[2] = g.ln[3] = g.ln[0];
618 		g.tr[1] = g.tr[2] = g.tr[3] = g.tr[0];
619 		g.width[1] = g.width[2] = g.width[3] = g.width[0];
620 	}
621 }
622 //-----------------------------------------------------------------------------
read_def()623 bool mglFont::read_def()
624 {
625 	// copy default factor for other font styles;
626 	fact[1] = fact[2] = fact[3] = fact[0] = mgl_fact*mgl_fgen;
627 	Buf = new short[mgl_cur];	// prealocate buffer
628 	memset(Buf,0,mgl_cur*sizeof(short));
629 	// now allocate memory for all fonts
630 	mem_alloc(mgl_numg);
631 	// and load symbols itself
632 #ifndef WIN32	// win32 don't initialized threads before main()
633 #pragma omp parallel for
634 #endif
635 	for(size_t i=0;i<mgl_numg;i++)
636 	{
637 		mglGlyphDescr &g = glyphs[i];
638 		g.id = mgl_gen_fnt[i][0];
639 		g.width[0] = g.width[1] = g.width[2] = g.width[3] = mgl_gen_fnt[i][1];
640 		g.numl[0] = g.numl[1] = g.numl[2] = g.numl[3] = mgl_gen_fnt[i][2];
641 		g.ln[0] = g.ln[1] = g.ln[2] = g.ln[3] = mgl_gen_fnt[i][3];
642 		g.numt[0] = g.numt[1] = g.numt[2] = g.numt[3] = mgl_gen_fnt[i][4];
643 		g.tr[0] = g.tr[1] = g.tr[2] = g.tr[3] = mgl_gen_fnt[i][5];
644 	}
645 	memcpy(Buf, mgl_buf_fnt, mgl_cur*sizeof(short));
646 	numb = mgl_cur;
647 	return true;
648 }
649 //-----------------------------------------------------------------------------
read_data(const char * fname,int s,std::vector<short> & buf,std::vector<mglGlyphDescr> & extra)650 bool mglFont::read_data(const char *fname, int s, std::vector<short> &buf, std::vector<mglGlyphDescr> &extra)
651 {
652 	gzFile fp;
653 	char str[256];
654 	int n, tmpw, tmpnl, tmpnt, retVal;
655 	unsigned ss, tmpi, tmppl, tmppt;
656 	fp = gzopen(fname,"r");	if(!fp)	return false;	// false if no file
657 	// first string is comment (not used), second string have information
658 	if(!gzgets(fp,str,256) || strncmp(str,"# font",6) || !gzgets(fp,str,256))
659 	{	gzclose(fp);	return false;	}
660 	retVal = sscanf(str, "%d%f%u", &n, fact+s, &ss);
661 	//Check sscanf read all data  (3 items)
662 	if(retVal != 3)	{	gzclose(fp);	return false;	}
663 
664 	for(int i=0;i<n;i++)
665 	{
666 		gzgets(fp,str,256);
667 		retVal = sscanf(str,"%u%d%d%u%d%u", &tmpi, &tmpw, &tmpnl, &tmppl, &tmpnt, &tmppt);
668 		if(retVal != 6)	{	gzclose(fp);	buf.clear();	return false;	}
669 		long j=Internal(unsigned(tmpi));
670 		if(j>=0)	// known symbol
671 		{
672 			mglGlyphDescr &g = glyphs[j];	g.width[s] = tmpw;
673 			g.ln[s] = -1-tmppl;		g.tr[s] = -1-tmppt;
674 			g.numl[s] = tmpnl;		g.numt[s] = tmpnt;
675 		}
676 		else
677 		{
678 			mglGlyphDescr g;	g.id = tmpi;
679 			g.width[0] = g.width[1] = g.width[2] = g.width[3] = tmpw;
680 			g.numl[0] = g.numl[1] = g.numl[2] = g.numl[3] = tmpnl;
681 			g.ln[0] = g.ln[1] = g.ln[2] = g.ln[3] = -1-tmppl;
682 			g.numt[0] = g.numt[1] = g.numt[2] = g.numt[3] = tmpnt;
683 			g.tr[0] = g.tr[1] = g.tr[2] = g.tr[3] = -1-tmppt;
684 #pragma omp critical
685 			extra.push_back(g);
686 		}
687 	}
688 	for(unsigned i=0;i<ss;i++)
689 	{
690 		for(int j=0;j<256;j++)	if((str[j] = gzgetc(fp))<=' ')	break;
691 		buf.push_back(atoi(str));
692 	}
693 	gzclose(fp);		// finish wire normal font
694 	return true;
695 }
696 //-----------------------------------------------------------------------------
read_main(const char * fname,std::vector<short> & buf)697 bool mglFont::read_main(const char *fname, std::vector<short> &buf)
698 {
699 	gzFile fp;
700 	int tmpi, tmpw, tmpnl, tmpnt;
701 	unsigned s, tmppl, tmppt,numg;
702 	char str[256];
703 
704 	fp = gzopen(fname,"r");	if(!fp)	return false;	// this font must be in any case
705 	// first string is comment (not used), second string have information
706 	if(!gzgets(fp,str,256) || strncmp(str,"# font",6) || !gzgets(fp,str,256))
707 	{	gzclose(fp);	return false;	}
708 	sscanf(str, "%u%f%u", &numg, fact, &s);
709 	fact[1] = fact[2] = fact[3] = fact[0];	// copy default factor for other font styles;
710 	// now allocate memory for all fonts
711 	mem_alloc(numg);
712 	// and load symbols itself
713 	for(size_t i=0;i<numg;i++)
714 	{
715 		gzgets(fp,str,256);
716 		sscanf(str,"%d%d%d%u%d%u", &tmpi, &tmpw, &tmpnl, &tmppl, &tmpnt, &tmppt);
717 		mglGlyphDescr &g = glyphs[i];	g.id = tmpi;
718 		g.width[0] = g.width[1] = g.width[2] = g.width[3] = tmpw;
719 		g.numl[0] = g.numl[1] = g.numl[2] = g.numl[3] = tmpnl;
720 		g.ln[0] = g.ln[1] = g.ln[2] = g.ln[3] = tmppl;
721 		g.numt[0] = g.numt[1] = g.numt[2] = g.numt[3] = tmpnt;
722 		g.tr[0] = g.tr[1] = g.tr[2] = g.tr[3] = tmppt;
723 	}
724 	for(unsigned i=0;i<s;i++)
725 	{
726 		for(int j=0;j<256;j++)	if((str[j] = gzgetc(fp))<=' ')	break;
727 		buf.push_back(atoi(str));
728 	}
729 	gzclose(fp);	// finish wire normal font
730 	return true;
731 }
732 //-----------------------------------------------------------------------------
FillY12()733 void mglFont::FillY12()
734 {
735 //#pragma omp parallel	// TODO problem at initialization of global object ... enable back after fixing global obj issue
736 	for(long i=0;i<long(glyphs.size());i++)
737 	{
738 		for(int s=0;s<4;s++)
739 		{
740 			int y1=0xffff, y2=-0xffff, nl=glyphs[i].numl[s];
741 			const short *ln = Buf+glyphs[i].ln[s];
742 			for(long k=0;k<nl;k++)
743 			{
744 				int y = ln[2*k+1];
745 				if(y==0x3fff)	continue;	// line breakthrough
746 				if(y<y1)	y1=y;
747 				if(y>y2)	y2=y;
748 			}
749 			glyphs[i].y1[s] = y1;
750 			glyphs[i].y2[s] = y2;
751 		}
752 	}
753 }
754 //-----------------------------------------------------------------------------
SaveBin(const char * fname)755 size_t mglFont::SaveBin(const char *fname)
756 {
757 	FILE *fp = fopen(fname,"wb");
758 	if(!fp)	return 0;
759 	size_t sum=0;
760 	fwrite(&numb,sizeof(size_t),1,fp);	sum += sizeof(size_t);
761 	fwrite(fact,sizeof(float),4,fp);	sum += sizeof(float)*4;
762 	fwrite(Buf,sizeof(short),numb,fp);	sum += sizeof(short)*numb;
763 	size_t len = glyphs.size();
764 	fwrite(&len,sizeof(size_t),1,fp);	sum += sizeof(long);
765 	fwrite(&(glyphs[0]),sizeof(mglGlyphDescr),len,fp);	sum += sizeof(mglGlyphDescr)*len;
766 	fclose(fp);	return sum;
767 }
768 //-----------------------------------------------------------------------------
LoadBin(const char * base,const char * path)769 bool mglFont::LoadBin(const char *base, const char *path)
770 {
771 	Clear();	// first clear old
772 	if(!path)	path = MGL_FONT_PATH;
773 	char str[256], sep='/';
774 	if(base && strstr(base,".vfmb"))
775 		snprintf(str,256,"%s%c%s",path,sep,base);
776 	else
777 		snprintf(str,256,"%s%c%s.vfmb",path,sep,base?base:"");
778 	str[255]=0;
779 	FILE *fp = fopen(str,"rb");		if(!fp)	return false;
780 	size_t s, len;
781 	bool res = true;
782 	s = fread(&numb,sizeof(size_t),1,fp);
783 	if(s<1)	res = false;
784 	s = fread(fact,sizeof(float),4,fp);
785 	if(s<4)	res = false;
786 	Buf = new short[numb];
787 	s = fread(Buf,sizeof(short),numb,fp);
788 	if(s<numb)	res = false;
789 	s = fread(&len,sizeof(size_t),1,fp);
790 	if(s<1)	res = false;
791 	if(res)
792 	{
793 		glyphs.clear();	glyphs.resize(len);
794 		s = fread(&(glyphs[0]),sizeof(mglGlyphDescr),len,fp);
795 		if(s<len)	res = false;
796 	}
797 //	if(!res)	Clear();
798 	fclose(fp);
799 	if(res)	FillY12();
800 	return res;
801 }
802 //-----------------------------------------------------------------------------
Load(const char * base,const char * path)803 bool mglFont::Load(const char *base, const char *path)
804 {
805 #ifdef WIN32
806 	char *buf=0, sep='\\';
807 #else
808 	char *buf=0, sep='/';
809 #endif
810 	char str[256];
811 	std::string loc = setlocale(LC_NUMERIC,"C");
812 	if(!path)	path = MGL_FONT_PATH;
813 	if(base && *base)	// try to load binary files
814 	{
815 		buf = new char[strlen(base)+1];
816 		strcpy(buf,base);
817 		if(strchr(buf,sep))
818 		{
819 			int i;
820 			for(i=strlen(buf);i>=0 && buf[i]!=sep;i--);
821 			path = buf;		buf[i]=0;	base = buf+i+1;
822 		}
823 		if(LoadBin(base,path))
824 		{	delete []buf;	return true;	}
825 	}
826 	Clear();	// first clear old
827 
828 	std::string sbase;
829 	if(base && strstr(base,".vfm"))	// bypass user-specified extension in base name
830 	{
831 		size_t len = strlen(base);
832 		sbase = std::string(base).substr(0,len-4);
833 		base = sbase.c_str();
834 	}
835 	snprintf(str,256,"%s%c%s.vfm",path,sep,base?base:"");	str[255]=0;
836 	std::vector<short> norm, bold, ital, both;
837 	if(!(base && *base) || !read_main(str,norm))
838 	{
839 		read_def();	setlocale(LC_NUMERIC,loc.c_str());
840 		if(buf)	delete []buf;
841 		FillY12();
842 		return true;
843 	}
844 	fact[1] = fact[2] = fact[3] = fact[0];
845 
846 	std::vector<mglGlyphDescr> ex_b,ex_i,ex_bi;
847 #pragma omp parallel sections
848 	{
849 		//================== bold ===========================================
850 #pragma omp section
851 		{	char str[256];	snprintf(str,256,"%s%c%s_b.vfm",path,sep,base);	// this file may absent
852 			str[255]=0;	read_data(str, 1, bold, ex_b);	}
853 
854 		//================== italic =========================================
855 #pragma omp section
856 		{	char str[256];	snprintf(str,256,"%s%c%s_i.vfm",path,sep,base);
857 			str[255]=0;	read_data(str, 2, ital, ex_i);	}
858 
859 		//================== bold-italic ====================================
860 #pragma omp section
861 		{	char str[256];	snprintf(str,256,"%s%c%s_bi.vfm",path,sep,base);
862 			str[255]=0;	read_data(str, 3, both, ex_bi);	}
863 	}
864 
865 	// now collect data
866 	numb = norm.size()+bold.size()+ital.size()+both.size();
867 	Buf = new short[numb];
868 	memcpy(Buf,&norm[0],norm.size()*sizeof(short));
869 	long cur = norm.size(), len = long(bold.size());
870 	if(bold.size()>0)
871 		memcpy(Buf+cur,&bold[0],bold.size()*sizeof(short));
872 #pragma omp parallel for
873 	for(long i=0;i<long(GetNumGlyph());i++)	if(glyphs[i].ln[1]<0)
874 	{	glyphs[i].ln[1] = cur-1-glyphs[i].ln[1];	glyphs[i].tr[1] = cur-1-glyphs[i].tr[1];	}
875 #pragma omp parallel for
876 	for(long i=0;i<long(ex_b.size());i++)	if(ex_b[i].ln[1]<0)
877 	{
878 		mglGlyphDescr &g = ex_b[i];
879 		g.ln[0] = g.ln[1] = g.ln[2] = g.ln[3] = cur-1-g.ln[1];
880 		g.tr[0] = g.tr[1] = g.tr[2] = g.tr[3] = cur-1-g.tr[1];
881 	}
882 	cur += len;		len = long(ital.size());
883 	if(ital.size()>0)
884 		memcpy(Buf+cur,&ital[0],ital.size()*sizeof(short));
885 #pragma omp parallel for
886 	for(long i=0;i<long(GetNumGlyph());i++)	if(glyphs[i].ln[2]<0)
887 	{	glyphs[i].ln[2] = cur-1-glyphs[i].ln[2];	glyphs[i].tr[2] = cur-1-glyphs[i].tr[2];	}
888 #pragma omp parallel for
889 	for(long i=0;i<long(ex_i.size());i++)	if(ex_i[i].ln[2]<0)
890 	{
891 		mglGlyphDescr &g = ex_i[i];
892 		g.ln[0] = g.ln[1] = g.ln[2] = g.ln[3] = cur-1-g.ln[2];
893 		g.tr[0] = g.tr[1] = g.tr[2] = g.tr[3] = cur-1-g.tr[2];
894 	}
895 	cur += len;
896 	if(both.size()>0)
897 		memcpy(Buf+cur,&both[0],both.size()*sizeof(short));
898 #pragma omp parallel for
899 	for(long i=0;i<long(GetNumGlyph());i++)	if(glyphs[i].ln[3]<0)
900 	{	glyphs[i].ln[3] = cur-1-glyphs[i].ln[3];	glyphs[i].tr[3] = cur-1-glyphs[i].tr[3];	}
901 #pragma omp parallel for
902 	for(long i=0;i<long(ex_bi.size());i++)	if(ex_bi[i].ln[3]<0)
903 	{
904 		mglGlyphDescr &g = ex_bi[i];
905 		g.ln[0] = g.ln[1] = g.ln[2] = g.ln[3] = cur-1-g.ln[3];
906 		g.tr[0] = g.tr[1] = g.tr[2] = g.tr[3] = cur-1-g.tr[3];
907 	}
908 	// now add missing symbols
909 	if(ex_b.size()==0)	ex_b = ex_i;
910 	else
911 	{
912 		for(size_t i=0;i<ex_i.size();i++)	// add from ex_i
913 		{
914 			long j = mgl_internal_code(ex_i[i].id, ex_b);
915 			if(j>=0)	// known symbol
916 			{
917 				mglGlyphDescr &g = ex_b[j], &f = ex_i[i];
918 				g.width[2] = f.width[2];
919 				g.ln[2] = f.ln[2];		g.tr[2] = f.tr[2];
920 				g.numl[2] = f.numl[2];	g.numt[2] = f.numt[2];
921 			}
922 			else	ex_b.push_back(ex_i[i]);
923 		}
924 		std::sort(ex_b.begin(),ex_b.end());
925 	}
926 	if(ex_b.size()==0)	ex_b = ex_bi;
927 	else
928 	{
929 		for(size_t i=0;i<ex_bi.size();i++)	// add from ex_bi
930 		{
931 			long j = mgl_internal_code(ex_bi[i].id, ex_b);
932 			if(j>=0)	// known symbol
933 			{
934 				mglGlyphDescr &g = ex_b[j], &f = ex_bi[i];
935 				g.width[2] = f.width[3];
936 				g.ln[2] = f.ln[3];		g.tr[2] = f.tr[3];
937 				g.numl[2] = f.numl[3];	g.numt[2] = f.numt[3];
938 			}
939 			else	ex_b.push_back(ex_bi[i]);
940 		}
941 		std::sort(ex_b.begin(),ex_b.end());
942 	}
943 	if(ex_b.size()>0)
944 	{
945 		glyphs.reserve(ex_b.size());	// pmgl_reallocate memory
946 		glyphs.insert(glyphs.end(), ex_b.begin(), ex_b.end());
947 		std::sort(glyphs.begin(),glyphs.end());
948 	}
949 
950 	// Finally normalize all factors
951 	fact[0] *= mgl_fgen;	fact[1] *= mgl_fgen;
952 	fact[2] *= mgl_fgen;	fact[3] *= mgl_fgen;
953 	FillY12();
954 	setlocale(LC_NUMERIC,loc.c_str());
955 	if(buf)	delete []buf;
956 	return true;
957 }
958 //-----------------------------------------------------------------------------
mglFont(const char * name,const char * path)959 mglFont::mglFont(const char *name, const char *path)
960 {
961 	parse = true;	gr=0;	Buf=0;	Hscale=1;
962 	if(name && *name)	Load(name, path);
963 	else	Load(MGL_DEF_FONT_NAME,0);
964 }
mglFont()965 mglFont::mglFont()
966 {
967 	parse = true;	gr=0;	Buf=0;	Hscale=1;
968 	if(!mglDefFont)	mgl_init();
969 	Copy(mglDefFont);
970 }
~mglFont()971 mglFont::~mglFont()	{	if(Buf)	delete []Buf;	}
Restore()972 void mglFont::Restore()	{	Copy(mglDefFont);	}
973 //-----------------------------------------------------------------------------
Clear()974 void mglFont::Clear()
975 {
976 //#pragma omp critical(font)
977 	{	if(Buf)	delete []Buf;	Buf=0;	glyphs.clear();	}
978 }
979 //-----------------------------------------------------------------------------
Copy(mglFont * f)980 void mglFont::Copy(mglFont *f)
981 {
982 	if(!f || f==this)	return;
983 #pragma omp critical(font)
984 	{	if(Buf)	delete []Buf;	Buf=0;	}
985 	// copy scale factors
986 	fact[0]=f->fact[0];	fact[1]=f->fact[1];	fact[2]=f->fact[2];	fact[3]=f->fact[3];
987 	// copy symbols descriptions
988 	numb = f->numb;	Buf = new short[numb];	memcpy(Buf, f->Buf, numb*sizeof(short));
989 	// copy symbol parameters
990 	glyphs.resize(f->glyphs.size());
991 	memcpy(&glyphs[0],&(f->glyphs)[0],glyphs.size()*sizeof(mglGlyphDescr));
992 }
993 //-----------------------------------------------------------------------------
mgl_check_tex_table()994 long MGL_EXPORT mgl_check_tex_table()
995 {
996 	size_t i=0;	while(mgl_tex_symb[i].tex[0])	i++;
997 	long res = 0;
998 	if(mgl_tex_num!=i)
999 	{	printf("real=%zu, set=%zu\n",i,mgl_tex_num);	res = -1;	}
1000 	for(i=0;mgl_tex_symb[i].tex[0];i++)
1001 	{
1002 		mglTeXsymb tst, *rts;	tst.tex = mgl_tex_symb[i].tex;
1003 		rts = (mglTeXsymb *) bsearch(&tst, mgl_tex_symb, mgl_tex_num, sizeof(mglTeXsymb), mgl_tex_symb_cmp);
1004 		if(!rts)
1005 		{	printf(_("Bad '%ls' at %zu\n"),mgl_tex_symb[i].tex,i);	res = 1+i;	}
1006 	}
1007 	return res;
1008 }
1009 //---------------------------------------------------------------------------
test_transl(const char * p)1010 bool static test_transl(const char *p)
1011 {
1012 	if(!p)	return false;
1013 #if MGL_USE_GETTEXT
1014 	std::string f = std::string(p) + "/ru/LC_MESSAGES/mathgl.mo";
1015 	FILE *fp = fopen(f.c_str(),"r");
1016 	if(fp)
1017 	{
1018 		bindtextdomain("mathgl", p);
1019 		textdomain("mathgl");
1020 		fclose(fp);	return true;
1021 	}
1022 #endif
1023 	return false;
1024 }
mgl_textdomain(const char * argv0,const char * loc)1025 void MGL_EXPORT mgl_textdomain(const char *argv0, const char *loc)
1026 {
1027 	static const char *argv=NULL;
1028 	if(!argv0)	argv0=argv;	else	argv=argv0;
1029 	setlocale(LC_ALL, loc);	setlocale(LC_NUMERIC, "C");
1030 #if MGL_USE_GETTEXT
1031 	if(!test_transl(MGL_INSTALL_DIR"/share/locale/"))
1032 		if(!test_transl("/usr/share/locale/"))
1033 			if(!test_transl("/usr/local/share/locale/"))
1034 			{
1035 				char* cwd = getcwd(NULL,0);
1036 				if(!test_transl(cwd))
1037 				{
1038 					free(cwd);
1039 					const char *f = argv0?strrchr(argv0,'/'):NULL;
1040 #ifdef WIN32
1041 					if(!f)	f = argv0?strrchr(argv0,'\\'):NULL;
1042 #endif
1043 					if(f)
1044 					{
1045 						std::string p(argv0,f-argv0);
1046 						if(!test_transl(p.c_str()))
1047 							return;
1048 					}
1049 					else	return;
1050 				}
1051 				else	if(cwd)	free(cwd);
1052 			}
1053 #endif
1054 }
mgl_textdomain_(const char * locale,int l)1055 void MGL_EXPORT mgl_textdomain_(const char *locale, int l)
1056 {	char *s=new char[l+1];	memcpy(s,locale,l);	s[l]=0;
1057 	mgl_textdomain(NULL,s);	delete []s;	}
1058 //---------------------------------------------------------------------------
1059