Doxygen
Loading...
Searching...
No Matches
FormulaManager Class Reference

#include <src/formula.h>

Classes

struct  Private
 

Public Member Functions

repository functions
void initFromRepository (const QCString &dir)
 
void checkRepositories ()
 
formula functions
void clear ()
 
int addFormula (const std::string &formulaText, int width=-1, int height=-1)
 
const FormulafindFormula (int formulaId) const
 
bool hasFormulas () const
 

Static Public Member Functions

static FormulaManagerinstance ()
 

Private Member Functions

void createFormulasTexFile (Dir &d, Format format, HighDPI hd, Mode mode)
 
void createLatexFile (const QCString &fileName, Format format, Mode mode, IntVector &formulasToGenerate)
 
 FormulaManager ()
 

Private Attributes

std::unique_ptr< Privatep
 

generator functions

enum class  Format { Bitmap , Vector }
 
enum class  HighDPI { On , Off }
 
enum class  Mode { Dark , Light }
 
void generateImages (const QCString &outputDir, Format format, HighDPI hd=HighDPI::Off)
 

Detailed Description

Manager class to handle formulas

Definition at line 58 of file formula.h.

Member Enumeration Documentation

◆ Format

enum class FormulaManager::Format
strong
Enumerator
Bitmap 
Vector 

Definition at line 79 of file formula.h.

79{ Bitmap, Vector };

◆ HighDPI

enum class FormulaManager::HighDPI
strong
Enumerator
On 
Off 

Definition at line 80 of file formula.h.

80{ On, Off };

◆ Mode

enum class FormulaManager::Mode
strong
Enumerator
Dark 
Light 

Definition at line 81 of file formula.h.

81{ Dark, Light };

Constructor & Destructor Documentation

◆ FormulaManager()

FormulaManager::FormulaManager ( )
private

Definition at line 50 of file formula.cpp.

50 : p(std::make_unique<Private>())
51{
52}
std::unique_ptr< Private > p
Definition formula.h:90

References p.

Referenced by instance().

Member Function Documentation

◆ addFormula()

int FormulaManager::addFormula ( const std::string & formulaText,
int width = -1,
int height = -1 )

Definition at line 691 of file formula.cpp.

692{
693 Formula *formula = p->formulas.find(formulaText);
694 if (formula) // same formula already stored
695 {
696 return formula->id();
697 }
698 // add new formula
699 int id = static_cast<int>(p->formulas.size());
700 formula = p->formulas.add(formulaText.c_str(),id,width,height);
701 p->formulaIdMap.emplace(id,formula);
702 return id;
703}
int id() const
Definition formula.h:36

References Formula::id(), and p.

Referenced by addFormula().

◆ checkRepositories()

void FormulaManager::checkRepositories ( )

Definition at line 173 of file formula.cpp.

174{
175 //printf("checkRepositories valid=%d\n",p->repositoriesValid);
176 if (!p->repositoriesValid)
177 {
178 clear(); // clear cached formulas, so the corresponding images and repository files
179 // are regenerated
180 p->repositoriesValid = true;
181 }
182}

References clear(), and p.

Referenced by parseInput().

◆ clear()

void FormulaManager::clear ( )

Definition at line 685 of file formula.cpp.

686{
687 p->formulas.clear();
688 p->formulaIdMap.clear();
689}

References p.

Referenced by checkRepositories(), cleanUpDoxygen(), and clearAll().

◆ createFormulasTexFile()

void FormulaManager::createFormulasTexFile ( Dir & d,
Format format,
HighDPI hd,
Mode mode )
private

Definition at line 553 of file formula.cpp.

554{
555 IntVector formulasToGenerate;
556 QCString formulaFileName = mode==Mode::Light ? "_formulas" : "_formulas_dark";
557 createLatexFile(formulaFileName,format,mode,formulasToGenerate);
558
559 if (!formulasToGenerate.empty()) // there are new formulas
560 {
561 if (!createDVIFile(formulaFileName)) return;
562
563 auto getFormula = [this](int pageNum) -> Formula *
564 {
565 auto it = p->formulaIdMap.find(pageNum);
566 if (it!=p->formulaIdMap.end())
567 {
568 return it->second;
569 }
570 return nullptr;
571 };
572
573 int pageIndex=1;
574 std::size_t numThreads = static_cast<std::size_t>(Config_getInt(NUM_PROC_THREADS));
575 if (numThreads>1) // multi-threaded version
576 {
577 ThreadPool threadPool(numThreads);
578 std::vector< std::future< StringVector > > results;
579 for (int pageNum : formulasToGenerate)
580 {
581 // create images for each formula.
582 auto formula = getFormula(pageNum);
583 auto processFormula = [=]() -> StringVector
584 {
585 return generateFormula(thisDir,formulaFileName,formula,pageNum,pageIndex,format,hd,mode);
586 };
587 results.emplace_back(threadPool.queue(processFormula));
588 pageIndex++;
589 }
590 for (auto &f : results)
591 {
592 auto tf = f.get();
593 p->tempFiles.insert(p->tempFiles.end(),tf.begin(),tf.end()); // append tf to p->tempFiles
594 }
595 }
596 else // single threaded version
597 {
598 for (int pageNum : formulasToGenerate)
599 {
600 // create images for each formula.
601 auto formula = getFormula(pageNum);
602 StringVector tf = generateFormula(thisDir,formulaFileName,formula,pageNum,pageIndex,format,hd,mode);
603 p->tempFiles.insert(p->tempFiles.end(),tf.begin(),tf.end()); // append tf to p->tempFiles
604
605 pageIndex++;
606 }
607 }
608 // remove intermediate files produced by latex
609 p->tempFiles.push_back(formulaFileName.str()+".dvi");
610 p->tempFiles.push_back(formulaFileName.str()+".log");
611 p->tempFiles.push_back(formulaFileName.str()+".aux");
612 }
613 // remove the latex file itself
614 p->tempFiles.push_back(formulaFileName.str()+".tex");
615
616 // write/update the formula repository so we know what text the
617 // generated images represent (we use this next time to avoid regeneration
618 // of the images, and to avoid forcing the user to delete all images in order
619 // to let a browser refresh the images).
620 std::ofstream f = Portable::openOutputStream("formula.repository");
621 if (f.is_open())
622 {
623 TextStream t(&f);
624 for (const auto &formula : p->formulas)
625 {
626 t << "\\_form#" << formula->id();
627 if (formula->width()!=-1 && formula->height()!=-1)
628 {
629 t << "=" << formula->width() << "x" << formula->height();
630 }
631 t << ":" << formula->text() << "\n";
632 }
633 }
634}
void createLatexFile(const QCString &fileName, Format format, Mode mode, IntVector &formulasToGenerate)
Definition formula.cpp:184
const std::string & str() const
Definition qcstring.h:526
#define Config_getInt(name)
Definition config.h:34
std::vector< int > IntVector
Definition containers.h:38
std::vector< std::string > StringVector
Definition containers.h:33
static StringVector generateFormula(const Dir &thisDir, const QCString &formulaFileName, Formula *formula, int pageNum, int pageIndex, FormulaManager::Format format, FormulaManager::HighDPI hd, FormulaManager::Mode mode)
Definition formula.cpp:473
static bool createDVIFile(const QCString &fileName)
Definition formula.cpp:241
std::ofstream openOutputStream(const QCString &name, bool append=false)
Definition portable.cpp:665

References Config_getInt, createDVIFile(), createLatexFile(), generateFormula(), Light, Portable::openOutputStream(), p, ThreadPool::queue(), and QCString::str().

Referenced by generateImages().

◆ createLatexFile()

void FormulaManager::createLatexFile ( const QCString & fileName,
Format format,
Mode mode,
IntVector & formulasToGenerate )
private

Definition at line 184 of file formula.cpp.

185{
186 // generate a latex file containing one formula per page.
187 QCString texName=fileName+".tex";
188 std::ofstream f = Portable::openOutputStream(texName);
189 if (f.is_open())
190 {
191 TextStream t(&f);
192 t << "\\documentclass{article}\n";
193 t << "\\usepackage{iftex}\n";
194 t << "\\usepackage{ifthen}\n";
195 t << "\\usepackage{epsfig}\n"; // for those who want to include images
196 t << "\\usepackage[utf8]{inputenc}\n"; // looks like some older distributions with newunicode package 1.1 need this option.
197 t << "\\usepackage{xcolor}\n";
198
199 if (mode==Mode::Dark) // invert page and text colors
200 {
201 t << "\\color{white}\n";
202 t << "\\pagecolor{black}\n";
203 }
204
207
208 QCString macroFile = Config_getString(FORMULA_MACROFILE);
209 if (!macroFile.isEmpty())
210 {
211 FileInfo fi(macroFile.str());
212 QCString stripMacroFile = fi.fileName();
213 t << "\\input{" << stripMacroFile << "}\n";
214 }
215
216 t << "\\pagestyle{empty}\n";
217 t << "\\begin{document}\n";
218 for (const auto &formula : p->formulas)
219 {
220 int id = formula->id();
221 // only formulas for which no image is cached are generated
222 //printf("check formula %d: cached=%d cachedDark=%d\n",formula->id(),formula->isCached(),formula->isCachedDark());
223 if ((mode==Mode::Light && !formula->isCached()) ||
224 (mode==Mode::Dark && !formula->isCachedDark())
225 )
226 {
227 // we force a pagebreak after each formula
228 t << formula->text() << "\n\\pagebreak\n\n";
229 formulasToGenerate.push_back(id);
230 }
231 QCString resultName;
232 resultName.sprintf("form_%d%s.%s",id, mode==Mode::Light?"":"_dark", format==Format::Vector?"svg":"png");
233 Doxygen::indexList->addImageFile(resultName);
234 }
235 t << "\\end{document}\n";
236 t.flush();
237 f.close();
238 }
239}
static IndexList * indexList
Definition doxygen.h:134
void addImageFile(const QCString &name)
Definition indexlist.h:126
bool isEmpty() const
Returns TRUE iff the string is empty.
Definition qcstring.h:150
QCString & sprintf(const char *format,...)
Definition qcstring.cpp:29
#define Config_getString(name)
Definition config.h:32
void writeExtraLatexPackages(TextStream &t)
void writeLatexSpecialFormulaChars(TextStream &t)

References IndexList::addImageFile(), Config_getString, Dark, FileInfo::fileName(), TextStream::flush(), Doxygen::indexList, QCString::isEmpty(), Light, Portable::openOutputStream(), p, QCString::sprintf(), QCString::str(), Vector, writeExtraLatexPackages(), and writeLatexSpecialFormulaChars().

Referenced by createFormulasTexFile().

◆ findFormula()

const Formula * FormulaManager::findFormula ( int formulaId) const

Definition at line 705 of file formula.cpp.

706{
707 auto it = p->formulaIdMap.find(formulaId);
708 return it != p->formulaIdMap.end() ? it->second : nullptr;
709}

References p.

Referenced by DocFormula::DocFormula(), and HtmlDocVisitor::operator()().

◆ generateImages()

void FormulaManager::generateImages ( const QCString & outputDir,
Format format,
HighDPI hd = HighDPI::Off )

Definition at line 636 of file formula.cpp.

637{
638 Dir d(path.str());
639 // store the original directory
640 if (!d.exists())
641 {
642 term("Output directory '%s' does not exist!\n",qPrint(path));
643 }
644 std::string oldDir = Dir::currentDirPath();
645
646 QCString macroFile = Config_getString(FORMULA_MACROFILE);
647 QCString stripMacroFile;
648 if (!macroFile.isEmpty())
649 {
650 FileInfo fi(macroFile.str());
651 macroFile=fi.absFilePath();
652 stripMacroFile = fi.fileName();
653 }
654
655 // go to the html output directory (i.e. path)
656 Dir::setCurrent(d.absPath());
657 Dir thisDir;
658
659 if (!macroFile.isEmpty())
660 {
661 copyFile(macroFile,stripMacroFile);
662 }
663
664 createFormulasTexFile(thisDir,format,hd,Mode::Light);
665 if (Config_getEnum(HTML_COLORSTYLE)!=HTML_COLORSTYLE_t::LIGHT) // all modes other than light need a dark version
666 {
667 // note that the dark version reuses the bounding box of the light version so it needs to be
668 // created after the light version.
669 createFormulasTexFile(thisDir,format,hd,Mode::Dark);
670 }
671
672 // clean up temporary files
674 {
675 for (const auto &file : p->tempFiles)
676 {
677 thisDir.remove(file);
678 }
679 }
680
681 // reset the directory to the original location.
682 Dir::setCurrent(oldDir);
683}
@ Formula
Definition debug.h:32
static bool isFlagSet(const DebugMask mask)
Definition debug.cpp:135
static std::string currentDirPath()
Definition dir.cpp:340
bool remove(const std::string &path, bool acceptsAbsPath=true) const
Definition dir.cpp:314
static bool setCurrent(const std::string &path)
Definition dir.cpp:348
void createFormulasTexFile(Dir &d, Format format, HighDPI hd, Mode mode)
Definition formula.cpp:553
#define Config_getEnum(name)
Definition config.h:35
#define term(fmt,...)
Definition message.h:94
const char * qPrint(const char *s)
Definition qcstring.h:661
bool copyFile(const QCString &src, const QCString &dest)
Copies the contents of file with name src to the newly created file with name dest.
Definition util.cpp:6169

References FileInfo::absFilePath(), Dir::absPath(), Config_getEnum, Config_getString, copyFile(), createFormulasTexFile(), Dir::currentDirPath(), Dark, Dir::exists(), FileInfo::fileName(), Debug::Formula, QCString::isEmpty(), Debug::isFlagSet(), Light, p, qPrint(), Dir::remove(), Dir::setCurrent(), QCString::str(), and term.

Referenced by generateOutput().

◆ hasFormulas()

bool FormulaManager::hasFormulas ( ) const

Definition at line 720 of file formula.cpp.

721{
722 return !p->formulas.empty();
723}

References p.

Referenced by generateOutput().

◆ initFromRepository()

void FormulaManager::initFromRepository ( const QCString & dir)

Definition at line 60 of file formula.cpp.

61{
62 std::ifstream f = Portable::openInputStream(dir+"/formula.repository");
63 if (f.is_open())
64 {
65 uint32_t formulaCount=0;
66 msg("Reading formula repository...\n");
67 std::string readLine;
68 std::string line;
69 std::string prefix("\\_form#");
70 int nextLineNr=1;
71 bool hasNextLine = !getline(f,readLine).fail();
72 while (hasNextLine)
73 {
74 line = readLine;
75 int lineNr = nextLineNr;
76
77 // look ahead a bit because a formula can be spread over several lines
78 while ((hasNextLine = !getline(f,readLine).fail()))
79 {
80 nextLineNr+=1;
81 if (!readLine.compare(0, prefix.size(), prefix)) break;
82 line += "\n" + readLine;
83 }
84
85 // new format: \_form#<digits>=<digits>x<digits>:formula
86 static const reg::Ex re_new(R"(\\_form#(\d+)=(\d+)x(\d+):)");
87 // old format: \_form#<digits>:formula
88 static const reg::Ex re_old(R"(\\_form#(\d+):)");
89
90 reg::Match match;
91 int id = -1;
92 int width = -1;
93 int height = -1;
94 std::string text;
95 if (reg::search(line,match,re_new)) // try new format first
96 {
97 id = std::stoi(match[1].str());
98 width = std::stoi(match[2].str());
99 height = std::stoi(match[3].str());
100 text = line.substr(match.position()+match.length());
101 //printf("new format found id=%d width=%d height=%d text=%s\n",id,width,height,text.c_str());
102 }
103 else if (reg::search(line,match,re_old)) // check for old format
104 {
105 //id = std::stoi(match[1].str());
106 //text = line.substr(match.position()+match.length());
107 //printf("old format found id=%d text=%s\n",id,text.c_str());
108 msg("old formula.repository format detected; forcing upgrade.\n");
109 p->repositoriesValid = false;
110 break;
111 }
112 else // unexpected content
113 {
114 warn_uncond("%s/formula.repository contains invalid content at line %d: found: '%s'\n",qPrint(dir),lineNr,line.c_str());
115 p->repositoriesValid = false;
116 break;
117 }
118
119 auto it = p->formulaIdMap.find(id);
120 Formula *formula=nullptr;
121 if (it!=p->formulaIdMap.end()) // formula already found in a repository for another output format
122 {
123 formula = it->second;
124 if (formula->text().str()!=text) // inconsistency between repositories detected
125 {
126 msg("differences detected between formula.repository files; forcing upgrade.\n");
127 p->repositoriesValid = false;
128 break;
129 }
130 formulaCount++;
131 }
132 else // create new formula from cache
133 {
134 //printf("formula not found adding it under id=%d\n",id);
135 formula = p->formulas.add(text.c_str(),id,width,height);
136 p->formulaIdMap.emplace(id,formula);
137 }
138
139 if (formula) // if an entry in the repository exists also check if there is a generated image
140 {
141 QCString formImgName;
142 formImgName.sprintf("form_%d",formula->id());
143 FileInfo fiPng((dir+"/"+formImgName+".png").str());
144 FileInfo fiSvg((dir+"/"+formImgName+".svg").str());
145 // mark formula as cached, so we do not need to regenerate the images
146 bool isCached = fiPng.exists() || fiSvg.exists();
147 formula->setCached(isCached);
148 //printf("formula %d: cached=%d\n",formula->id(),isCached);
149
150 FileInfo fiPngDark((dir+"/"+formImgName+"_dark.png").str());
151 FileInfo fiSvgDark((dir+"/"+formImgName+"_dark.svg").str());
152 bool isCachedDark = fiPngDark.exists() || fiSvgDark.exists();
153 formula->setCachedDark(isCachedDark);
154 //printf("formula %d: cachedDark=%d\n",formula->id(),isCachedDark);
155 }
156 }
157
158 // For the first repository all formulas should be new (e.g. formulaCount==0).
159 // For the other repositories the same number of formulas should be found
160 // (and number of formulas should be the same for all repositories, content is already check above)
161 if (formulaCount>0 && formulaCount!=p->formulas.size()) // inconsistency between repositories
162 {
163 msg("differences detected between formula.repository files; forcing upgrade.\n");
164 p->repositoriesValid = false;
165 }
166 }
167 else // no repository found for an output format
168 {
169 p->repositoriesValid = false;
170 }
171}
constexpr auto prefix
Definition anchor.cpp:44
void setCachedDark(bool cached)
Definition formula.h:46
QCString text() const
Definition formula.h:37
void setCached(bool cached)
Definition formula.h:45
void msg(const char *fmt,...)
Definition message.cpp:98
#define warn_uncond(fmt,...)
Definition message.h:79
std::ifstream openInputStream(const QCString &name, bool binary=false, bool openAtEnd=false)
Definition portable.cpp:676
bool search(std::string_view str, Match &match, const Ex &re, size_t pos)
Search in a given string str starting at position pos for a match against regular expression re.
Definition regex.cpp:748
bool match(std::string_view str, Match &match, const Ex &re)
Matches a given string str for a match against regular expression re.
Definition regex.cpp:759

References FileInfo::exists(), Formula::id(), msg(), Portable::openInputStream(), p, prefix, qPrint(), reg::search(), Formula::setCached(), Formula::setCachedDark(), QCString::sprintf(), QCString::str(), Formula::text(), and warn_uncond.

Referenced by parseInput().

◆ instance()

FormulaManager & FormulaManager::instance ( )
static

Definition at line 54 of file formula.cpp.

55{
56 static FormulaManager fm;
57 return fm;
58}

References FormulaManager().

Referenced by addFormula(), cleanUpDoxygen(), clearAll(), DocFormula::DocFormula(), generateOutput(), HtmlDocVisitor::operator()(), and parseInput().

Member Data Documentation

◆ p


The documentation for this class was generated from the following files: