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