/*************************************************************************** * font.cpp is part of Math Graphic Library * Copyright (C) 2007-2016 Alexey Balakin * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 3 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include #include #include #if !defined(__BORLANDC__) || (__CODEGEARC__ >= 0x0630) #include #else #include #endif #include "mgl2/base.h" #include "mgl2/font.h" #include "def_font.cc" #include "tex_table.cc" //----------------------------------------------------------------------------- //mglFont mglDefFont("nofont"); mglFont mglDefFont; //----------------------------------------------------------------------------- long MGL_EXPORT_PURE mgl_internal_code(unsigned s, const std::vector &glyphs) { register long i1=0,i2=glyphs.size()-1; register wchar_t j = wchar_t(s & MGL_FONT_MASK); // let suppose that id[i]glyphs[i].id) i1=i+1; else return i; } return j==glyphs[i2].id ? i2 : -1; } //----------------------------------------------------------------------------- bool MGL_EXPORT mglGetStyle(const char *how, int *font, int *align) { bool col=false; if(align) *align = 1; // centering text by default if(!how || *how==0) return col; // NOTE: no brightness for text color for(;*how && *how!=':';how++) { if(strchr(MGL_COLORS,*how)) col = true; if(*how=='{' && how[1]=='x') col = true; } if(align) { *align = 1; if(strchr(how,'R')) *align = 2; if(strchr(how,'C')) *align = 1; if(strchr(how,'L')) *align = 0; if(strchr(how,'D')) *align+= 4; } if(font) { *font = 0; if(strchr(how,'b')) *font = *font|MGL_FONT_BOLD; if(strchr(how,'i')) *font = *font|MGL_FONT_ITAL; if(strchr(how,'w')) *font = *font|MGL_FONT_WIRE; if(strchr(how,'o')) *font = *font|MGL_FONT_OLINE; if(strchr(how,'u')) *font = *font|MGL_FONT_ULINE; } return col; } //----------------------------------------------------------------------------- float mglFont::Puts(const char *str,const char *how,float c1,float c2) const { int font=0, align=1; float w=0; mglGetStyle(how,&font,&align); MGL_TO_WCS(str,w = Puts(wcs,font,align,c1,c2)); return w; } //----------------------------------------------------------------------------- float mglFont::Width(const char *str,const char *how) const { int font=0; float w=0; mglGetStyle(how,&font); MGL_TO_WCS(str,w = Width(wcs,font)); return w; } //----------------------------------------------------------------------------- float mglFont::Puts(const wchar_t *str,const char *how,float c1,float c2) const { int font=0, align=1; mglGetStyle(how,&font,&align); return Puts(str, font, align,c1,c2); } //----------------------------------------------------------------------------- float mglFont::Width(const wchar_t *str,const char *how) const { int font=0; mglGetStyle(how,&font); return Width(str, font); } //----------------------------------------------------------------------------- float mglFont::Puts(const wchar_t *str,int font,int align, float c1,float c2) const { if(GetNumGlyph()==0 || !str || *str==0) return 0; float ww=0,w=0,h = (align&4) ? 500./fact[0] : 0; size_t size = mgl_wcslen(str)+1,num=0; if(parse) { unsigned *wcs = new unsigned[size], *buf=wcs; memcpy(wcs,str,size*sizeof(wchar_t)); Convert(str, wcs); for(size_t i=0;wcs[i];i++) { if(wcs[i]=='\n') // parse '\n' symbol { wcs[i]=0; w = Puts(buf,0,0,1.f,0x10|font,c1,c2); // find width Puts(buf,-w*(align&3)/2.f,-h - 500.*num/fact[0],1.f,font,c1,c2); // draw it really buf=wcs+i+1; num++; if(w>ww) ww=w; } if(wcs[i]=='\\' && wcs[i+1]=='n' && (wcs[i+2]>' ' || wcschr(L"{}[]()!@#$%^&*/-?.,_=+\\\"", wcs[i+2]))) // parse '\n' symbol { wcs[i]=0; w = Puts(buf,0,0,1.f,0x10|font,c1,c2); // find width Puts(buf,-w*(align&3)/2.f,-h - 500.*num/fact[0],1.f,font,c1,c2); // draw it really buf=wcs+i+2; num++; if(w>ww) ww=w; } } // draw string itself w = Puts(buf,0,0,1.f,0x10|font,c1,c2); // find width Puts(buf,-w*(align&3)/2.f,-h - 500.*num/fact[0],1.f,font,c1,c2); // draw it really if(w>ww) ww=w; delete []wcs; } else { int s = (font/MGL_FONT_BOLD)&3; h *= fact[0]/fact[s]; for(size_t i=0;iGlyph(w, -h, 1, (s+(font&MGL_FONT_WIRE))?4:0, j, c1+i*(c2-c1)/(size-1)); } w+= GetWidth(s,j)/fact[s]; } } return ww; } //----------------------------------------------------------------------------- float mglFont::Width(const wchar_t *str,int font) const { if(GetNumGlyph()==0 || !str || *str==0) return 0; float ww=0,w=0; size_t size = mgl_wcslen(str)+1; if(parse) { unsigned *wcs = new unsigned[size], *buf=wcs; memcpy(wcs,str,size*sizeof(wchar_t)); Convert(str, wcs); for(size_t i=0;wcs[i];i++) if(wcs[i]=='\n') // parse '\n' symbol { wcs[i]=0; w = Puts(buf,0,0,1.,0x10|font,'k','k'); // find width buf=wcs+i+1; if(w>ww) ww=w; } w = Puts(buf,0,0,1.,0x10|font,'k','k'); if(wtex, bb->tex); } //----------------------------------------------------------------------------- // parse LaTeX commands (mostly symbols and acents, and some font-style commands) unsigned mglFont::Parse(const wchar_t *s) const { register long k; unsigned res = unsigned(-2); // Default is no symbol if(!s || !s[0]) return res; // for(k=0;mgl_tex_symb[k].kod;k++); // determine the number of symbols mglTeXsymb tst, *rts; tst.tex = s; rts = (mglTeXsymb *) bsearch(&tst, mgl_tex_symb, mgl_tex_num, sizeof(mglTeXsymb), mgl_tex_symb_cmp); if(rts) return rts->kod; // for(k=0;mgl_tex_symb[k].kod;k++) // special symbols // if(!wcscmp(s,mgl_tex_symb[k].tex)) // return mgl_tex_symb[k].kod; for(k=0;mgl_act_symb[k].kod;k++) // acents if(!wcscmp(s,mgl_act_symb[k].tex)) return mgl_act_symb[k].kod | MGL_FONT_ZEROW; // arbitrary UTF symbol if(s[0]=='u' && s[1]=='t' && s[2]=='f') // { wscanf(s+3,"%lx",&k); return wchar_t(k); } { k = wcstoul(s+3,NULL,16); return wchar_t(k); } // font/style changes for next symbol if(!wcscmp(s,L"big")) res = unsigned(-5); else if(!wcscmp(s,L"frac")) res = unsigned(-6); else if(!wcscmp(s,L"stack")) res = unsigned(-7); else if(!wcscmp(s,L"overset")) res = unsigned(-8); else if(!wcscmp(s,L"underset")) res = unsigned(-9); else if(!wcscmp(s,L"stackr")) res = unsigned(-10); else if(!wcscmp(s,L"stackl")) res = unsigned(-11); else if(!wcscmp(s,L"sub")) res = unsigned(-12); else if(!wcscmp(s,L"sup")) res = unsigned(-13); else if(!wcscmp(s,L"textsc")) res = unsigned(-14); // new else if(!wcscmp(s,L"b")) res = MGL_FONT_BOLD; else if(!wcscmp(s,L"i")) res = MGL_FONT_ITAL; else if(!wcscmp(s,L"bi")) res = MGL_FONT_BOLD|MGL_FONT_ITAL; else if(!wcscmp(s,L"r")) res = unsigned(-1); else if(!wcscmp(s,L"a")) res = MGL_FONT_OLINE; else if(!wcscmp(s,L"u")) res = MGL_FONT_ULINE; else if(!wcscmp(s,L"n")) res = '\n'; else if(!wcscmp(s,L"overline")) res = MGL_FONT_OLINE; else if(!wcscmp(s,L"underline"))res = MGL_FONT_ULINE; else if(!wcscmp(s,L"textbf")) res = MGL_FONT_BOLD; else if(!wcscmp(s,L"textit")) res = MGL_FONT_ITAL; else if(!wcscmp(s,L"textrm")) res = unsigned(-1); else if(!wcscmp(s,L"T2A")) res = unsigned(-1); else if(!wcscmp(s,L"w")) res = MGL_FONT_WIRE; else if(!wcscmp(s,L"wire")) res = MGL_FONT_WIRE; else if(!wcsncmp(s,L"color",5)) res = MGL_COLOR_MASK + (0xff & s[5]); return res; } //----------------------------------------------------------------------------- void mglFont::Convert(const wchar_t *str, unsigned *res) const { register size_t r,i,j,k,i0; wchar_t s[128]=L""; // TeX command and current char for(i=j=0;str[i];i++) { wchar_t ch = str[i]; if(ch=='\\') // It can be TeX command { if(wcschr(L"{}_^\\@# ",str[i+1])) // No, it is usual symbol res[j++] = str[++i]; else // Yes, it is TeX command { i0=i+1; for(k=0;isalnum(str[++i]) && k<127;k++) s[k] = str[i]; s[k] = 0; r = Parse(s); if(r==unsigned(-2)) // command not found, so use next symbol itself { res[j++] = str[i0]; i = i0; } else if(r) { res[j++] = r; if(str[i]>' ') i--; if(str[i]==0) break; } } } else if(ch=='-' && str[i+1]=='-') { res[j++] = 0x2212; i++; } else if(ch=='\b'){} else if(ch<=' ' && ch!='\n') res[j++] = ' '; // no \t at this moment :( else if(ch=='_') res[j++] = MGL_FONT_LOWER; else if(ch=='^') res[j++] = MGL_FONT_UPPER; else if(ch=='@') res[j++] = MGL_FONT_UPPER|MGL_FONT_LOWER; else if(ch=='{') res[j++] = unsigned(-3); else if(ch=='}') res[j++] = unsigned(-4); else if(ch=='#' && str[i+1]>' ') res[j++] = MGL_COLOR_MASK + (0xff & str[++i]); // TODO inline colors -- stack of RGBA colors + index else res[j++] = ch; // It is just symbol } res[j] = 0; } //----------------------------------------------------------------------------- float mglFont::get_ptr(long &i,unsigned *str, unsigned **b1, unsigned **b2,float &w1,float &w2, float f1, float f2, int st) const { static unsigned s1[2]={0,0}, s2[2]={0,0}; register long k; i++; if(str[i]==unsigned(-3)) { i++; *b1 = str+i; for(k=1;k>0 && str[i];i++) { if(str[i]==unsigned(-4)) k--; if(str[i]==unsigned(-3)) k++; } str[i-1]=0; } else { s1[0] = str[i]; *b1 = s1; i++; } if(str[i]==unsigned(-3)) { i++; *b2 = str+i; for(k=1;k>0 && str[i];i++) { if(str[i]==unsigned(-4)) k--; if(str[i]==unsigned(-3)) k++; } str[i-1]=0; } else { s2[0] = str[i]; *b2 = s2; i++; } i--; w1 = Puts(*b1, 0, 0, f1, 0x10|st,'k','k'); w2 = Puts(*b2, 0, 0, f2, 0x10|st,'k','k'); return w1>w2 ? w1 : w2; } //----------------------------------------------------------------------------- void mglFont::draw_ouline(int st, float x, float y, float f, float g, float ww, float ccol) const { if(st&MGL_FONT_OLINE) gr->Glyph(x,y+499*f/g, ww*g, (st&MGL_FONT_WIRE)?12:8, 0, ccol); if(st&MGL_FONT_ULINE) gr->Glyph(x,y-200*f/g, ww*g, (st&MGL_FONT_WIRE)?12:8, 0, ccol); } //----------------------------------------------------------------------------- #define MGL_CLEAR_STYLE {st = style; yy = y; ff = f; ccol=c1+dc*i; a = (st/MGL_FONT_BOLD)&3;} float mglFont::Puts(const unsigned *text, float x,float y,float f,int style,float c1,float c2) const { if(GetNumGlyph()==0) return 0; float w=0; // string width int st = style; // current style unsigned *b1, *b2; // pointer to substring unsigned *str; // string itself float yy=y, ff=f, ww, w1, w2; int a = (st/MGL_FONT_BOLD)&3; long i; for(i=0;text[i];i++); float dc=i>1?(c2-c1)/(i-1):0; str = new unsigned[i+1]; memcpy(str,text,(i+1)*sizeof(unsigned)); float ccol = 0; for(long i=0;str[i];i++) { ccol = ccol<0?ccol:c1+dc*i; unsigned s = str[i]; ww = 0; if(s==unsigned(-3)) // recursion call here { i++; b1 = str+i; for(long k=1;k>0 && str[i];i++) { if(str[i]==unsigned(-4)) k--; if(str[i]==unsigned(-3)) k++; } str[i-1]=0; i--; ww = Puts(b1, x, yy, ff, (st&(~MGL_FONT_OLINE)&(~MGL_FONT_ULINE)), ccol,ccol); if(gr && !(style&0x10)) // add under-/over- line now draw_ouline(st,x,y,f,fact[a],ww,ccol); MGL_CLEAR_STYLE } else if(s=='\n') // newline { ww = get_ptr(i, str, &b1, &b2, w1, w2, ff, ff, st); Puts(b1, x+(ww-w1)/2, yy, ff, (st&(~MGL_FONT_OLINE)&(~MGL_FONT_ULINE)), ccol,ccol); Puts(b2, x+(ww-w2)/2, yy-600*ff/fact[a], ff, (st&(~MGL_FONT_OLINE)&(~MGL_FONT_ULINE)), ccol,ccol); MGL_CLEAR_STYLE } else if(s==unsigned(-9)) // underset { ww = get_ptr(i, str, &b1, &b2, w1, w2, ff, ff/4, st); Puts(b1, x+(ww-w1)/2, yy, ff, (st&(~MGL_FONT_OLINE)&(~MGL_FONT_ULINE)), ccol,ccol); Puts(b2, x+(ww-w2)/2, yy-150*ff/fact[a], ff/4, (st&(~MGL_FONT_OLINE)&(~MGL_FONT_ULINE)), ccol,ccol); if(gr && !(style&0x10)) // add under-/over- line now draw_ouline(st,x,y,f,fact[a],ww,ccol); MGL_CLEAR_STYLE } else if(s==unsigned(-8)) // overset { ww = get_ptr(i, str, &b1, &b2, w1, w2, ff, ff/4, st); Puts(b1, x+(ww-w1)/2, yy, ff, (st&(~MGL_FONT_OLINE)&(~MGL_FONT_ULINE)), ccol,ccol); Puts(b2, x+(ww-w2)/2, yy+375*ff/fact[a], ff/4, (st&(~MGL_FONT_OLINE)&(~MGL_FONT_ULINE)), ccol,ccol); if(gr && !(style&0x10)) // add under-/over- line now draw_ouline(st,x,y,f,fact[a],ww,ccol); MGL_CLEAR_STYLE } else if(s==unsigned(-12)) // sub { ww = get_ptr(i, str, &b1, &b2, w1, w2, ff, ff/4, st); Puts(b1, x+(ww-w1)/2, yy, ff, (st&(~MGL_FONT_OLINE)&(~MGL_FONT_ULINE)), ccol,ccol); Puts(b2, x+(ww-w2)/2, yy-250*ff/fact[a], ff/4, (st&(~MGL_FONT_OLINE)&(~MGL_FONT_ULINE)), ccol,ccol); if(gr && !(style&0x10)) // add under-/over- line now draw_ouline(st,x,y,f,fact[a],ww,ccol); MGL_CLEAR_STYLE } else if(s==unsigned(-13)) // sup { ww = get_ptr(i, str, &b1, &b2, w1, w2, ff, ff/4, st); Puts(b1, x+(ww-w1)/2, yy, ff, (st&(~MGL_FONT_OLINE)&(~MGL_FONT_ULINE)), ccol,ccol); Puts(b2, x+(ww-w2)/2, yy+450*ff/fact[a], ff/4, (st&(~MGL_FONT_OLINE)&(~MGL_FONT_ULINE)), ccol,ccol); if(gr && !(style&0x10)) // add under-/over- line now draw_ouline(st,x,y,f,fact[a],ww,ccol); MGL_CLEAR_STYLE } else if(s==unsigned(-11)) // stackl { ww = get_ptr(i, str, &b1, &b2, w1, w2, ff*0.45, ff*0.45, st); Puts(b1, x, yy+250*ff/fact[a], ff*0.45, (st&(~MGL_FONT_OLINE)&(~MGL_FONT_ULINE)), ccol,ccol); Puts(b2, x, yy-110*ff/fact[a], ff*0.45, (st&(~MGL_FONT_OLINE)&(~MGL_FONT_ULINE)), ccol,ccol); if(gr && !(style&0x10)) // add under-/over- line now draw_ouline(st,x,y,f,fact[a],ww,ccol); MGL_CLEAR_STYLE } else if(s==unsigned(-10)) // stacr { ww = get_ptr(i, str, &b1, &b2, w1, w2, ff*0.45, ff*0.45, st); Puts(b1, x+(ww-w1), yy+250*ff/fact[a], ff*0.45, (st&(~MGL_FONT_OLINE)&(~MGL_FONT_ULINE)), ccol,ccol); Puts(b2, x+(ww-w2), yy-110*ff/fact[a], ff*0.45, (st&(~MGL_FONT_OLINE)&(~MGL_FONT_ULINE)), ccol,ccol); if(gr && !(style&0x10)) // add under-/over- line now draw_ouline(st,x,y,f,fact[a],ww,ccol); MGL_CLEAR_STYLE } else if(s==unsigned(-7)) // stack { ww = get_ptr(i, str, &b1, &b2, w1, w2, ff*0.45, ff*0.45, st); Puts(b1, x+(ww-w1)/2, yy+250*ff/fact[a], ff*0.45, (st&(~MGL_FONT_OLINE)&(~MGL_FONT_ULINE)), ccol,ccol); Puts(b2, x+(ww-w2)/2, yy-110*ff/fact[a], ff*0.45, (st&(~MGL_FONT_OLINE)&(~MGL_FONT_ULINE)), ccol,ccol); if(gr && !(style&0x10)) // add under-/over- line now draw_ouline(st,x,y,f,fact[a],ww,ccol); MGL_CLEAR_STYLE } else if(s==unsigned(-6)) // frac { ww = get_ptr(i, str, &b1, &b2, w1, w2, ff*0.45, ff*0.45, st); Puts(b1, x+(ww-w1)/2, yy+250*ff/fact[a], ff*0.45, (st&(~MGL_FONT_OLINE)&(~MGL_FONT_ULINE)), ccol,ccol); Puts(b2, x+(ww-w2)/2, yy-110*ff/fact[a], ff*0.45, (st&(~MGL_FONT_OLINE)&(~MGL_FONT_ULINE)), ccol,ccol); if(gr && !(style&0x10)) // add under-/over- line now { draw_ouline(st,x,y,f,fact[a],ww,ccol); gr->Glyph(x,y+150*f/fact[a], ww*fact[a], (st&MGL_FONT_WIRE)?12:8, 0, ccol); } MGL_CLEAR_STYLE } else if(s==unsigned(-4)) MGL_CLEAR_STYLE // should be never here but if I miss sth ... else if(s==unsigned(-14)) // script symbols { long k=1; if(str[i+1]==unsigned(-3)) for(long j=i+2;k>0 && str[j];j++) { if(str[j]==unsigned(-3)) k++; if(str[j]==unsigned(-4)) k--; if(iswlower(str[j])) str[j] = MGL_FONT_UPPER|MGL_FONT_LOWER|towupper(str[j]); } } else if(s==unsigned(-5)) // large symbol ff *= 1.5; else if(s==unsigned(-1)) // set normal font st = style & MGL_FONT_ROMAN; else if((s&MGL_COLOR_MASK)==MGL_COLOR_MASK) // color specification ccol = -float(s & 0xff); // TODO inline colors -- make textures else { unsigned ss = s&MGL_FONT_MASK; if(ss) // draw symbol (glyph) { long j = Internal('!'); float dx=0; if(ss>' ') { j = Internal(ss); if(j==-1) continue; if(s & MGL_FONT_ZEROW) { long j=1; yy += 100*ff/fact[a]; while(str[i+j]>=unsigned(-15)) j++; unsigned sn = str[i+j]; if(sn' ') // specially center { dx = 0.75*ff*(GetWidth(a,Internal(sn&MGL_FONT_MASK))-GetWidth(a,j))/fact[a]; if(dx<0) dx=0; } } if(gr && !(style&0x10)) { if(st & MGL_FONT_WIRE) gr->Glyph(x+dx,yy,ff,a+4,j,ccol); else gr->Glyph(x+dx,yy,ff,a,j,ccol); } } ww = ff*GetWidth(a,j)/fact[a]; if(gr && !(style&0x10)) // add under-/over- line now draw_ouline(st,x,y,f,fact[a],ww,ccol); if(s & MGL_FONT_ZEROW) ww = 0; MGL_CLEAR_STYLE } // apply new styles if(s/MGL_FONT_BOLD) st = st | (s & MGL_FONT_STYLE); a = (st/MGL_FONT_BOLD)&3; ss = (s/MGL_FONT_UPPER)%4; if(ss) { if(ss==1) { ff *=0.6; yy += 200*ff/fact[a]; } // = 500*0.4 else if(ss==2) { ff *=0.6; yy -= 80*ff/fact[a]; } // = -500*0.16 else if(ss==3) { ff *=0.8; yy += 0*60*ff/fact[a]; } // = 500*0.12 } } x += ww; w += ww; } delete []str; return w; } //----------------------------------------------------------------------------- // copy normal style as default for other styles void mglFont::main_copy() { #pragma omp parallel for for(long i=0;i &buf, std::vector &extra) { gzFile fp; char str[256]; int n, tmpw, tmpnl, tmpnt, retVal; unsigned ss, tmpi, tmppl, tmppt; fp = gzopen(fname,"r"); if(!fp) return false; // false if no file // first string is comment (not used), second string have information if(!gzgets(fp,str,256) || strncmp(str,"# font",6) || !gzgets(fp,str,256)) { gzclose(fp); return false; } retVal = sscanf(str, "%d%f%u", &n, fact+s, &ss); //Check sscanf read all data (3 items) if(retVal != 3) { gzclose(fp); return false; } for(int i=0;i=0) // known symbol { mglGlyphDescr &g = glyphs[j]; g.width[s] = tmpw; g.ln[s] = -1-tmppl; g.tr[s] = -1-tmppt; g.numl[s] = tmpnl; g.numt[s] = tmpnt; } else { mglGlyphDescr g; g.id = tmpi; g.width[0] = g.width[1] = g.width[2] = g.width[3] = tmpw; g.numl[0] = g.numl[1] = g.numl[2] = g.numl[3] = tmpnl; g.ln[0] = g.ln[1] = g.ln[2] = g.ln[3] = -1-tmppl; g.numt[0] = g.numt[1] = g.numt[2] = g.numt[3] = tmpnt; g.tr[0] = g.tr[1] = g.tr[2] = g.tr[3] = -1-tmppt; #pragma omp critical extra.push_back(g); } } for(unsigned i=0;i &buf) { gzFile fp; int tmpi, tmpw, tmpnl, tmpnt; unsigned s, tmppl, tmppt,numg; char str[256]; fp = gzopen(fname,"r"); if(!fp) return false; // this font must be in any case // first string is comment (not used), second string have information if(!gzgets(fp,str,256) || strncmp(str,"# font",6) || !gzgets(fp,str,256)) { gzclose(fp); return false; } sscanf(str, "%u%f%u", &numg, fact, &s); fact[1] = fact[2] = fact[3] = fact[0]; // copy default factor for other font styles; // now allocate memory for all fonts mem_alloc(numg); // and load symbols itself for(size_t i=0;i=0 && buf[i]!=sep;i--); path = buf; buf[i]=0; base = buf+i+1; } if(LoadBin(base,path)) { delete []buf; return true; } } Clear(); // first clear old snprintf(str,256,"%s%c%s.vfm",path,sep,base?base:""); str[255]=0; std::vector norm, bold, ital, both; if(!(base && *base) || !read_main(str,norm)) { read_def(); setlocale(LC_NUMERIC,loc.c_str()); if(buf) delete []buf; return true; } fact[1] = fact[2] = fact[3] = fact[0]; std::vector ex_b,ex_i,ex_bi; #pragma omp parallel sections { //================== bold =========================================== #pragma omp section { char str[256]; snprintf(str,256,"%s%c%s_b.vfm",path,sep,base); // this file may absent str[255]=0; read_data(str, 1, bold, ex_b); } //================== italic ========================================= #pragma omp section { char str[256]; snprintf(str,256,"%s%c%s_i.vfm",path,sep,base); str[255]=0; read_data(str, 2, ital, ex_i); } //================== bold-italic ==================================== #pragma omp section { char str[256]; snprintf(str,256,"%s%c%s_bi.vfm",path,sep,base); str[255]=0; read_data(str, 3, both, ex_bi); } } // now collect data numb = norm.size()+bold.size()+ital.size()+both.size(); Buf = new short[numb]; memcpy(Buf,&norm[0],norm.size()*sizeof(short)); long cur = norm.size(), len = long(bold.size()); if(bold.size()>0) memcpy(Buf+cur,&bold[0],bold.size()*sizeof(short)); #pragma omp parallel for for(long i=0;i0) memcpy(Buf+cur,&ital[0],ital.size()*sizeof(short)); #pragma omp parallel for for(long i=0;i0) memcpy(Buf+cur,&both[0],both.size()*sizeof(short)); #pragma omp parallel for for(long i=0;i=0) // known symbol { mglGlyphDescr &g = ex_b[j], &f = ex_i[i]; g.width[2] = f.width[2]; g.ln[2] = f.ln[2]; g.tr[2] = f.tr[2]; g.numl[2] = f.numl[2]; g.numt[2] = f.numt[2]; } else ex_b.push_back(ex_i[i]); } std::sort(ex_b.begin(),ex_b.end()); } if(ex_b.size()==0) ex_b = ex_bi; else { for(size_t i=0;i=0) // known symbol { mglGlyphDescr &g = ex_b[j], &f = ex_bi[i]; g.width[2] = f.width[3]; g.ln[2] = f.ln[3]; g.tr[2] = f.tr[3]; g.numl[2] = f.numl[3]; g.numt[2] = f.numt[3]; } else ex_b.push_back(ex_bi[i]); } std::sort(ex_b.begin(),ex_b.end()); } if(ex_b.size()>0) { glyphs.reserve(ex_b.size()); // preallocate memory glyphs.insert(glyphs.end(), ex_b.begin(), ex_b.end()); std::sort(glyphs.begin(),glyphs.end()); } // Finally normalize all factors fact[0] *= mgl_fgen; fact[1] *= mgl_fgen; fact[2] *= mgl_fgen; fact[3] *= mgl_fgen; setlocale(LC_NUMERIC,loc.c_str()); if(buf) delete []buf; return true; } //----------------------------------------------------------------------------- #if MGL_HAVE_PTHREAD extern pthread_mutex_t mutexRnd; #endif //----------------------------------------------------------------------------- float mgl_cos[360]; void MGL_NO_EXPORT mgl_init() { #if MGL_HAVE_PTHREAD pthread_mutex_init(&mutexRnd,0); #endif #ifndef WIN32 // win32 don't initialized threads before main() #pragma omp parallel for #endif for(long i=0;i<360;i++) mgl_cos[i] = cos(i*M_PI/180.); } //----------------------------------------------------------------------------- mglFont::mglFont(const char *name, const char *path) { parse = true; gr=0; Buf=0; // if(this==&mglDefFont) Load(name, path); else Copy(&mglDefFont); if(name && *name) Load(name, path); else if(this!=&mglDefFont) Copy(&mglDefFont); else { mgl_init(); // NOTE: this call init function for the library. Load(MGL_DEF_FONT_NAME,0); } } mglFont::~mglFont() { if(Buf) delete []Buf; } void mglFont::Restore() { Copy(&mglDefFont); } //----------------------------------------------------------------------------- void mglFont::Clear() { //#pragma omp critical(font) { if(Buf) delete []Buf; Buf=0; glyphs.clear(); } } //----------------------------------------------------------------------------- void mglFont::Copy(mglFont *f) { if(!f || f==this) return; #pragma omp critical(font) { if(Buf) delete []Buf; Buf=0; } // copy scale factors memcpy(fact,f->fact,4*sizeof(float)); // copy symbols descriptions numb = f->numb; Buf = new short[numb]; memcpy(Buf, f->Buf, numb*sizeof(short)); // copy symbol parameters glyphs.resize(f->glyphs.size()); memcpy(&glyphs[0],&(f->glyphs)[0],glyphs.size()*sizeof(mglGlyphDescr)); } //----------------------------------------------------------------------------- long MGL_EXPORT mgl_check_tex_table() { size_t i=0; while(mgl_tex_symb[i].tex[0]) i++; long res = 0; if(mgl_tex_num!=i) { printf("real=%zu, set=%zu\n",i,mgl_tex_num); res = -1; } for(i=0;mgl_tex_symb[i].tex[0];i++) { mglTeXsymb tst, *rts; tst.tex = mgl_tex_symb[i].tex; rts = (mglTeXsymb *) bsearch(&tst, mgl_tex_symb, mgl_tex_num, sizeof(mglTeXsymb), mgl_tex_symb_cmp); if(!rts) { printf("Bad '%ls' at %zu\n",mgl_tex_symb[i].tex,i); res = 1+i; } } return res; }