Doxygen
Loading...
Searching...
No Matches
htmldocvisitor.cpp
Go to the documentation of this file.
1/******************************************************************************
2 *
3 * Copyright (C) 1997-2020 by Dimitri van Heesch.
4 *
5 * Permission to use, copy, modify, and distribute this software and its
6 * documentation under the terms of the GNU General Public License is hereby
7 * granted. No representations are made about the suitability of this software
8 * for any purpose. It is provided "as is" without express or implied warranty.
9 * See the GNU General Public License for more details.
10 *
11 * Documents produced by Doxygen are derivative works derived from the
12 * input used in their production; they are not affected by this license.
13 *
14 */
15
16#include "htmldocvisitor.h"
17#include "docparser.h"
18#include "language.h"
19#include "doxygen.h"
20#include "outputgen.h"
21#include "outputlist.h"
22#include "dot.h"
23#include "message.h"
24#include "config.h"
25#include "htmlgen.h"
26#include "parserintf.h"
27#include "msc.h"
28#include "dia.h"
29#include "util.h"
30#include "vhdldocgen.h"
31#include "filedef.h"
32#include "memberdef.h"
33#include "htmlentity.h"
34#include "emoji.h"
35#include "plantuml.h"
36#include "mermaid.h"
37#include "formula.h"
38#include "fileinfo.h"
39#include "indexlist.h"
40#include "portable.h"
41#include "codefragment.h"
42#include "cite.h"
43#include "md5.h"
44
45static const int NUM_HTML_LIST_TYPES = 4;
46static const char g_types[][NUM_HTML_LIST_TYPES] = {"1", "a", "i", "A"};
47enum class contexts_t
48{
49 NONE, // 0
50 STARTLI, // 1
51 STARTDD, // 2
52 ENDLI, // 3
53 ENDDD, // 4
54 STARTTD, // 5
55 ENDTD, // 6
56 INTERLI, // 7
57 INTERDD, // 8
59};
60
61static constexpr const char *contexts(contexts_t type)
62{
63 switch (type)
64 {
65 case contexts_t::NONE: return nullptr;
66 case contexts_t::STARTLI: return "startli";
67 case contexts_t::STARTDD: return "startdd";
68 case contexts_t::ENDLI: return "endli";
69 case contexts_t::ENDDD: return "enddd";
70 case contexts_t::STARTTD: return "starttd";
71 case contexts_t::ENDTD: return "endtd";
72 case contexts_t::INTERLI: return "interli";
73 case contexts_t::INTERDD: return "interdd";
74 case contexts_t::INTERTD: return "intertd";
75 default: return nullptr;
76 }
77}
78static const char *hex="0123456789ABCDEF";
79
81{
82 static int cnt = 0;
83 QCString result="a";
84 QCString cntStr;
85 result += cntStr.setNum(cnt);
86 result += "_";
87 cnt++;
88 const char *str = word.data();
89 unsigned char c = 0;
90 if (str)
91 {
92 while ((c = *str++))
93 {
94 if ((c >= 'a' && c <= 'z') || // ALPHA
95 (c >= 'A' && c <= 'Z') || // ALPHA
96 (c >= '0' && c <= '9') || // DIGIT
97 c == '-' ||
98 c == '.'
99 )
100 {
101 result += c;
102 }
103 else
104 {
105 char enc[4];
106 enc[0] = '_';
107 enc[1] = hex[(c & 0xf0) >> 4];
108 enc[2] = hex[c & 0xf];
109 enc[3] = 0;
110 result += enc;
111 }
112 }
113 }
114 return result;
115}
116
117
118
120{
121 //printf("mustBeOutsideParagraph(%s)=",docNodeName(n));
124 /* <table> */ DocHtmlTable,
125 /* <h?> */ DocSection, DocHtmlHeader,
126 /* \internal */ DocInternal,
127 /* <div> */ DocInclude, DocSecRefList,
128 /* <hr> */ DocHorRuler,
129 /* <blockquote> */ DocHtmlBlockQuote,
130 /* \parblock */ DocParBlock,
131 /* \dotfile */ DocDotFile,
132 /* \mscfile */ DocMscFile,
133 /* \diafile */ DocDiaFile,
134 /* \plantumlfile */ DocPlantUmlFile,
135 /* \mermaidfile */ DocMermaidFile,
136 /* <details> */ DocHtmlDetails,
137 /* <summary> */ DocHtmlSummary,
138 DocIncOperator >(n))
139 {
140 return TRUE;
141 }
142 const DocVerbatim *dv = std::get_if<DocVerbatim>(&n);
143 if (dv)
144 {
145 DocVerbatim::Type t = dv->type();
147 return t!=DocVerbatim::HtmlOnly || dv->isBlock();
148 }
149 const DocStyleChange *sc = std::get_if<DocStyleChange>(&n);
150 if (sc)
151 {
152 return sc->style()==DocStyleChange::Preformatted ||
153 sc->style()==DocStyleChange::Div ||
155 }
156 const DocFormula *df = std::get_if<DocFormula>(&n);
157 if (df)
158 {
159 return !df->isInline();
160 }
161 const DocImage *di = std::get_if<DocImage>(&n);
162 if (di)
163 {
164 return !di->isInlineImage();
165 }
166 return FALSE;
167}
168
170{
171 switch (s.type())
172 {
178 return FALSE;
179 default:
180 return TRUE;
181 }
182}
183
184static bool isDocIncludeVisible(const DocInclude &s)
185{
186 switch (s.type())
187 {
194 return FALSE;
195 default:
196 return TRUE;
197 }
198}
199
201{
202 switch (s.type())
203 {
205 return FALSE;
206 default:
207 return TRUE;
208 }
209}
210
211static bool isInvisibleNode(const DocNodeVariant &node)
212{
213 //printf("isInvisibleNode(%s)\n",docNodeName(node));
214 // skip over white space
215 const DocWhiteSpace *ws = std::get_if<DocWhiteSpace>(&node);
216 if (ws) return true;
217 // skip over image nodes that are not for HTML output
218 const DocImage *di = std::get_if<DocImage>(&node);
219 if (di) return di->type()!=DocImage::Html;
220 // skip over verbatim nodes that are not visible in the HTML output
221 const DocVerbatim *dv = std::get_if<DocVerbatim>(&node);
222 if (dv) return !isDocVerbatimVisible(*dv);
223 // skip over include nodes that are not visible in the HTML output
224 const DocInclude *dinc = std::get_if<DocInclude>(&node);
225 if (dinc) return !isDocIncludeVisible(*dinc);
226 const DocIncOperator *dio = std::get_if<DocIncOperator>(&node);
227 // skip over include operator nodes that are not visible in the HTML output
228 if (dio) return !isDocIncOperatorVisible(*dio);
229 return false;
230}
231
232//-------------------------------------------------------------------------
233
235 const Definition *ctx,const QCString &fn)
236 : m_t(t), m_ci(ci), m_ctx(ctx), m_fileName(fn)
237{
238 if (ctx) m_langExt=ctx->getDefFileExtension();
239}
240
241template<class T>
243{
244 if (n.hasCaption())
245 {
246 t << "<div class=\"caption\">\n";
247 for (const auto &child : n.children())
248 {
249 std::visit(*this, child);
250 }
251 t << "</div>\n";
252 }
253}
254
255 //--------------------------------------
256 // visitor functions for leaf nodes
257 //--------------------------------------
258
260{
261 if (m_hide) return;
262 filter(w.word());
263}
264
266{
267 if (m_hide) return;
268 //printf("linked word: %s\n",qPrint(w.word()));
269 startLink(w.ref(),w.file(),w.relPath(),w.anchor(),w.tooltip());
270 filter(w.word());
271 endLink();
272}
273
275{
276 if (m_hide) return;
277 if (m_insidePre)
278 {
279 m_t << w.chars();
280 }
281 else
282 {
283 m_t << " ";
284 }
285}
286
288{
289 if (m_hide) return;
290 if (m_insideTitle &&
291 (s.symbol()==HtmlEntityMapper::Sym_Quot || s.symbol()==HtmlEntityMapper::Sym_quot)) // escape "'s inside title="..."
292 {
293 m_t << "&quot;";
294 }
295 else
296 {
297 const char *res = HtmlEntityMapper::instance().html(s.symbol());
298 if (res)
299 {
300 m_t << res;
301 }
302 else
303 {
304 err("HTML: non supported HTML-entity found: {}\n",
306 }
307 }
308}
309
311{
312 if (m_hide) return;
313 const char *res = EmojiEntityMapper::instance().unicode(s.index());
314 if (res)
315 {
316 m_t << "<span class=\"emoji\">" << res << "</span>";
317 }
318 else
319 {
320 m_t << s.name();
321 }
322}
323
325{
326 if (!Config_getBool(OBFUSCATE_EMAILS))
327 {
328 m_t << "<a href=\"mailto:" << url << "\">";
329 }
330 else
331 {
332 m_t << "<a href=\"#\" onclick=\"location.href='mai'+'lto:'";
333 if (!url.isEmpty())
334 {
335 const char *p = url.data();
336 uint32_t size=3;
337 while (*p)
338 {
339 m_t << "+'";
340 for (uint32_t j=0;j<size && *p;j++)
341 {
342 p = writeUTF8Char(m_t,p);
343 }
344 m_t << "'";
345 if (size==3) size=2; else size=3;
346 }
347 }
348 m_t << "; return false;\">";
349 }
350}
351
353{
354 if (m_hide) return;
355 if (u.isEmail()) // mail address
356 {
357 QCString url = u.url();
358 // obfuscate the mail address link
360 if (!Config_getBool(OBFUSCATE_EMAILS))
361 {
362 m_t << url;
363 }
364 else
365 {
366 const char *p = url.data();
367 // also obfuscate the address as shown on the web page
368 uint32_t size=5;
369 while (*p)
370 {
371 for (uint32_t j=0;j<size && *p;j++)
372 {
373 p = writeUTF8Char(m_t,p);
374 }
375 if (*p) m_t << "<span class=\"obfuscator\">.nosp@m.</span>";
376 if (size==5) size=4; else size=5;
377 }
378 }
379 m_t << "</a>";
380 }
381 else // web address
382 {
383 m_t << "<a href=\"";
384 filter(u.url());
385 m_t << "\">";
386 filter(u.url());
387 m_t << "</a>";
388 }
389}
390
392{
393 if (m_hide) return;
394 m_t << "<br "<< br.attribs().toString() << " />\n";
395}
396
398{
399 if (m_hide) return;
401 m_t << "<hr "<< hr.attribs().toString() << " />\n";
403}
404
406{
407 if (m_hide) return;
408 switch (s.style())
409 {
411 if (s.enable()) m_t << "<b" << s.attribs().toString() << ">"; else m_t << "</b>";
412 break;
414 if (s.enable()) m_t << "<s" << s.attribs().toString() << ">"; else m_t << "</s>";
415 break;
417 if (s.enable()) m_t << "<strike" << s.attribs().toString() << ">"; else m_t << "</strike>";
418 break;
420 if (s.enable()) m_t << "<del" << s.attribs().toString() << ">"; else m_t << "</del>";
421 break;
423 if (s.enable()) m_t << "<u" << s.attribs().toString() << ">"; else m_t << "</u>";
424 break;
426 if (s.enable()) m_t << "<ins" << s.attribs().toString() << ">"; else m_t << "</ins>";
427 break;
429 if (s.enable())
430 {
431 auto attribs = s.attribs();
432 if (s.tagName()=="a")
433 {
434 attribs.mergeAttribute("class","arg");
435 }
436 m_t << "<em" << attribs.toString() << ">";
437 }
438 else
439 {
440 m_t << "</em>";
441 }
442 break;
444 if (s.enable()) m_t << "<kbd" << s.attribs().toString() << ">"; else m_t << "</kbd>";
445 break;
447 if (s.enable())
448 {
449 m_t << "<span class=\"tt\"" << s.attribs().toString() << ">";
450 m_insidePre=true;
451 }
452 else
453 {
454 m_t << "</span>";
455 m_insidePre=false;
456 }
457 break;
459 if (s.enable())
460 {
461 auto attribs = s.attribs();
462 if (s.tagName()=="p")
463 {
464 attribs.mergeAttribute("class","param");
465 }
466 m_t << "<code" << attribs.toString() << ">";
467 m_insidePre=true;
468 }
469 else
470 {
471 m_insidePre=false;
472 m_t << "</code>";
473 }
474 break;
476 if (s.enable()) m_t << "<sub" << s.attribs().toString() << ">"; else m_t << "</sub>";
477 break;
479 if (s.enable()) m_t << "<sup" << s.attribs().toString() << ">"; else m_t << "</sup>";
480 break;
482 if (s.enable())
483 {
485 m_t << "<center" << s.attribs().toString() << ">";
486 }
487 else
488 {
489 m_t << "</center>";
491 }
492 break;
494 if (s.enable()) m_t << "<small" << s.attribs().toString() << ">"; else m_t << "</small>";
495 break;
497 if (s.enable()) m_t << "<cite" << s.attribs().toString() << ">"; else m_t << "</cite>";
498 break;
500 if (s.enable())
501 {
503 m_t << "<pre" << s.attribs().toString() << ">";
505 }
506 else
507 {
509 m_t << "</pre>";
511 }
512 break;
514 if (s.enable())
515 {
517 m_t << "<div" << s.attribs().toString() << ">";
518 }
519 else
520 {
521 m_t << "</div>";
523 }
524 break;
526 if (s.enable()) m_t << "<span" << s.attribs().toString() << ">"; else m_t << "</span>";
527 break;
528 }
529}
530
531///--------------------------------------------------------------------------------------
532
534{
535 if (m_hide) return;
536 QCString lang = m_langExt;
537 if (!s.language().isEmpty()) // explicit language setting
538 {
539 lang = s.language();
540 }
541 SrcLangExt langExt = getLanguageFromCodeLang(lang);
542 switch(s.type())
543 {
546 m_ci.startCodeFragment("DoxyCode");
548 s.context(),
549 s.text(),
550 langExt,
551 Config_getBool(STRIP_CODE_COMMENTS),
553 .setExample(s.isExample(), s.exampleFile())
554 .setInlineFragment(true)
556 );
557 m_ci.endCodeFragment("DoxyCode");
559 break;
562 m_t << "<pre class=\"fragment\">";
563 filter(s.text());
564 m_t << "</pre>";
566 break;
568 filter(s.text(), true);
569 break;
571 m_t << "<code class=\"JavaDocCode\">";
572 filter(s.text(), true);
573 m_t << "</code>";
574 break;
576 {
577 if (s.isBlock()) forceEndParagraph(s);
578 m_t << s.text();
579 if (s.isBlock()) forceStartParagraph(s);
580 }
581 break;
587 /* nothing */
588 break;
589
590 case DocVerbatim::Dot:
591 {
593
594 bool exists = false;
595 auto fileName = writeFileContents(Config_getString(HTML_OUTPUT)+"/inline_dotgraph_", // baseName
596 ".dot", // extension
597 s.text(), // contents
598 exists);
599 if (!fileName.isEmpty())
600 {
601 m_t << "<div class=\"dotgraph\">\n";
602 writeDotFile(fileName,s.relPath(),s.context(),s.srcFile(),s.srcLine(),!exists);
603 visitCaption(m_t, s);
604 m_t << "</div>\n";
605 }
606
608 }
609 break;
610 case DocVerbatim::Msc:
611 {
613
614 bool exists = false;
615 auto fileName = writeFileContents(Config_getString(HTML_OUTPUT)+"/inline_mscgraph_", // baseName
616 ".msc", // extension
617 "msc {"+s.text()+"}", // contents
618 exists);
619 if (!fileName.isEmpty())
620 {
621 m_t << "<div class=\"mscgraph\">\n";
622 writeMscFile(fileName,s.relPath(),s.context(),s.srcFile(),s.srcLine(),!exists);
623 visitCaption(m_t, s);
624 m_t << "</div>\n";
625 }
626
628 }
629 break;
631 {
633 QCString htmlOutput = Config_getString(HTML_OUTPUT);
635 PlantumlManager::OutputFormat format = PlantumlManager::PUML_BITMAP; // default : PUML_BITMAP
636 if (imgExt=="svg")
637 {
639 }
640 auto baseNameVector = PlantumlManager::instance().writePlantUMLSource(
641 htmlOutput,s.exampleFile(),
642 s.text(),format,s.engine(),s.srcFile(),s.srcLine(),true);
643 for (const auto &baseName: baseNameVector)
644 {
645 m_t << "<div class=\"plantumlgraph\">\n";
646 writePlantUMLFile(baseName,s.relPath(),s.context(),s.srcFile(),s.srcLine());
647 visitCaption(m_t, s);
648 m_t << "</div>\n";
649 }
651 }
652 break;
654 {
656 if (Config_getEnum(MERMAID_RENDER_MODE)==MERMAID_RENDER_MODE_t::CLI) // CLI mode: pre-generate image via mmdc
657 {
658 auto htmlOutput = Config_getString(HTML_OUTPUT);
659 auto outputFormat = MermaidManager::OutputFormat::HTML;
660 auto imageFormat = MermaidManager::convertToImageFormat(outputFormat);
662 htmlOutput,s.exampleFile(),
663 s.text(),imageFormat,s.srcFile(),s.srcLine());
664 m_t << "<div class=\"mermaidgraph\">\n";
665 writeMermaidFile(baseName,s.relPath(),s.context(),s.srcFile(),s.srcLine());
666 visitCaption(m_t, s);
667 m_t << "</div>\n";
668 }
669 else // CLIENT_SIDE or AUTO mode: embed for client-side rendering
670 {
671 m_t << "<div class=\"mermaidgraph\">\n";
672 m_t << "<pre class=\"mermaid\">\n";
673 m_t << convertToHtml(s.text());
674 m_t << "</pre>\n";
675 visitCaption(m_t, s);
676 m_t << "</div>\n";
677 }
679 }
680 break;
681 }
682}
683
685{
686 if (m_hide) return;
687 m_t << "<a class=\"anchor\" id=\"" << anc.anchor() << "\"" << anc.attribs().toString() << "></a>";
688}
689
691{
692 if (m_hide) return;
694 switch(inc.type())
695 {
698 m_ci.startCodeFragment("DoxyCode");
700 inc.context(),
701 inc.text(),
702 langExt,
703 inc.stripCodeComments(),
705 .setExample(inc.isExample(), inc.exampleFile())
706 .setInlineFragment(true)
707 .setShowLineNumbers(false)
709 );
710 m_ci.endCodeFragment("DoxyCode");
712 break;
714 {
716 m_ci.startCodeFragment("DoxyCode");
717 FileInfo cfi( inc.file().str() );
718 auto fd = createFileDef( cfi.dirPath(), cfi.fileName() );
720 inc.context(),
721 inc.text(),
722 langExt,
723 inc.stripCodeComments(),
725 .setExample(inc.isExample(), inc.exampleFile())
726 .setFileDef(fd.get())
727 .setInlineFragment(true)
729 );
730 m_ci.endCodeFragment("DoxyCode");
732 }
733 break;
741 break;
743 {
744 if (inc.isBlock()) forceEndParagraph(inc);
745 m_t << inc.text();
746 if (inc.isBlock()) forceStartParagraph(inc);
747 }
748 break;
751 m_t << "<pre class=\"fragment\">";
752 filter(inc.text());
753 m_t << "</pre>";
755 break;
759 m_ci.startCodeFragment("DoxyCode");
761 inc.file(),
762 inc.blockId(),
763 inc.context(),
765 inc.trimLeft(),
767 );
768 m_ci.endCodeFragment("DoxyCode");
770 break;
771 }
772}
773
775{
776 //printf("DocIncOperator: type=%d first=%d, last=%d text='%s'\n",
777 // op.type(),op.isFirst(),op.isLast(),qPrint(op.text()));
778 if (op.isFirst())
779 {
781 if (!m_hide) m_ci.startCodeFragment("DoxyCode");
783 m_hide=TRUE;
784 }
786 if (locLangExt.isEmpty()) locLangExt = m_langExt;
787 SrcLangExt langExt = getLanguageFromFileName(locLangExt);
788 if (op.type()!=DocIncOperator::Skip)
789 {
790 m_hide = popHidden();
791 if (!m_hide)
792 {
793 std::unique_ptr<FileDef> fd;
794 if (!op.includeFileName().isEmpty())
795 {
796 FileInfo cfi( op.includeFileName().str() );
797 fd = createFileDef( cfi.dirPath(), cfi.fileName() );
798 }
799 getCodeParser(locLangExt).parseCode(
800 m_ci,
801 op.context(),
802 op.text(),
803 langExt,
806 .setExample(op.isExample(), op.exampleFile())
807 .setFileDef(fd.get())
808 .setStartLine(op.line())
811 );
812 }
814 m_hide=TRUE;
815 }
816 if (op.isLast())
817 {
818 m_hide = popHidden();
819 if (!m_hide) m_ci.endCodeFragment("DoxyCode");
821 }
822 else
823 {
824 if (!m_hide) m_t << "\n";
825 }
826}
827
829{
830 if (m_hide) return;
831 bool bDisplay = !f.isInline();
832 if (bDisplay)
833 {
835 m_t << "<p class=\"formulaDsp\">\n";
836 }
837
838 if (Config_getBool(USE_MATHJAX))
839 {
840 QCString text = f.text();
841 bool closeInline = FALSE;
842 if (!bDisplay && !text.isEmpty() && text.at(0)=='$' &&
843 text.at(text.length()-1)=='$')
844 {
845 closeInline=TRUE;
846 text = text.mid(1,text.length()-2);
847 m_t << "\\(";
848 }
849 else if (!bDisplay && !text.isEmpty())
850 {
851 closeInline=TRUE;
852 m_t << "\\(";
853 }
854 m_t << convertToHtml(text);
855 if (closeInline)
856 {
857 m_t << "\\)";
858 }
859 }
860 else
861 {
862 const Formula *formula = FormulaManager::instance().findFormula(f.id());
863
864 enum class ImageType { Light, Dark };
865 enum class Visibility { Always, Dark, Light, AutoDark, AutoLight };
866 auto writeFormula = [&](ImageType imgType,Visibility visibility) -> QCString {
867 // see https://chipcullen.com/how-to-have-dark-mode-image-that-works-with-user-choice for the design idea
868 TextStream t;
869 QCString extension = Config_getEnum(HTML_FORMULA_FORMAT)==HTML_FORMULA_FORMAT_t::svg ? ".svg":".png" ;
870 if (visibility==Visibility::AutoDark || visibility==Visibility::AutoLight)
871 {
872 t << "<picture>";
873 t << "<source srcset=\"" << f.relPath() << f.name();
874 if (visibility==Visibility::AutoDark)
875 {
876 t << extension;
877 t << "\" media=\"(prefers-color-scheme: light)\"";
878 }
879 else // AutoLight
880 {
881 t << "_dark";
882 t << extension;
883 t << "\" media=\"(prefers-color-scheme: dark)\"";
884 }
885 t << "/>";
886 }
887 t << "<img class=\"formula";
888 t << (bDisplay ? "Dsp" : "Inl");
889 if (visibility==Visibility::Light) t << " light-mode-visible";
890 else if (visibility==Visibility::Dark) t << " dark-mode-visible";
891 t << "\" alt=\"" << filterQuotedCdataAttr(f.text()) << "\"" << " src=\"" << f.relPath() << f.name();
892 if (imgType==ImageType::Dark) t << "_dark";
893 t << extension;
894 if (formula && formula->width()!=-1)
895 {
896 t << "\" width=\"";
897 t << formula->width();
898 }
899 if (formula && formula->height()!=-1)
900 {
901 t << "\" height=\"";
902 t << formula->height();
903 }
904 t << "\"/>";
905 if (visibility==Visibility::AutoDark || visibility==Visibility::AutoLight)
906 {
907 t << "</picture>";
908 }
909 return t.str();
910 };
911
912 auto colorStyle = Config_getEnum(HTML_COLORSTYLE);
913 switch(colorStyle)
914 {
915 case HTML_COLORSTYLE_t::LIGHT:
916 m_t << writeFormula(ImageType::Light,Visibility::Always);
917 break;
918 case HTML_COLORSTYLE_t::DARK:
919 m_t << writeFormula(ImageType::Dark, Visibility::Always);
920 break;
921 case HTML_COLORSTYLE_t::AUTO_LIGHT:
922 m_t << writeFormula(ImageType::Light, Visibility::AutoLight);
923 break;
924 case HTML_COLORSTYLE_t::AUTO_DARK:
925 m_t << writeFormula(ImageType::Dark, Visibility::AutoDark);
926 break;
927 case HTML_COLORSTYLE_t::TOGGLE:
928 // write the image twice and use javascript (darkmode_toggle.js) to show only one of them
929 m_t << writeFormula(ImageType::Light,Visibility::Light);
930 m_t << writeFormula(ImageType::Dark, Visibility::Dark);
931 break;
932 }
933 }
934 if (bDisplay)
935 {
936 m_t << "\n</p>\n";
938 }
939}
940
942{
944 if (e.member())
945 {
946 anchor.prepend(e.member()->anchor()+"_");
947 }
948 m_t << "<a id=\"" << anchor << "\" name=\"" << anchor << "\"></a>";
949 //printf("*** DocIndexEntry: word='%s' scope='%s' member='%s'\n",
950 // qPrint(e.entry()),
951 // e.scope() ? qPrint(e.scope()->name()) : "<null>",
952 // e.member() ? qPrint(e.member()->name()) : "<null>"
953 // );
954 Doxygen::indexList->addIndexItem(e.scope(),e.member(),anchor,e.entry());
955}
956
958{
959 m_t << "</dd>\n";
960 m_t << "<dd>\n";
961}
962
964{
965 if (m_hide) return;
966 auto opt = cite.option();
967 if (!cite.file().isEmpty())
968 {
969 if (!opt.noCite()) startLink(cite.ref(),cite.file(),cite.relPath(),cite.anchor());
970 filter(cite.getText());
971 if (!opt.noCite()) endLink();
972 }
973 else
974 {
975 m_t << "<b>";
976 if (!opt.noPar()) filter("[");
977 filter(cite.target());
978 if (!opt.noPar()) filter("]");
979 m_t << "</b>";
980 }
981}
982
983
984//--------------------------------------
985// visitor functions for compound nodes
986//--------------------------------------
987
988
990{
991 //printf("DocAutoList::visitPre\n");
992 if (m_hide) return;
994 if (l.isEnumList())
995 {
996 //
997 // Do list type based on depth:
998 // 1.
999 // a.
1000 // i.
1001 // A.
1002 // 1. (repeat)...
1003 //
1004 m_t << "<ol type=\"" << g_types[l.depth() % NUM_HTML_LIST_TYPES] << "\">";
1005 }
1006 else
1007 {
1008 if (l.isCheckedList())
1009 {
1010 m_t << "<ul class=\"check\">";
1011 }
1012 else
1013 {
1014 m_t << "<ul>";
1015 }
1016 }
1017 if (!l.isPreformatted()) m_t << "\n";
1018 visitChildren(l);
1019 if (l.isEnumList())
1020 {
1021 m_t << "</ol>";
1022 }
1023 else
1024 {
1025 m_t << "</ul>";
1026 }
1027 if (!l.isPreformatted()) m_t << "\n";
1029}
1030
1032{
1033 if (m_hide) return;
1034 switch (li.itemNumber())
1035 {
1036 case DocAutoList::Unchecked: // unchecked
1037 m_t << "<li class=\"unchecked\">";
1038 break;
1039 case DocAutoList::Checked_x: // checked with x
1040 case DocAutoList::Checked_X: // checked with X
1041 m_t << "<li class=\"checked\">";
1042 break;
1043 default:
1044 m_t << "<li>";
1045 break;
1046 }
1047 visitChildren(li);
1048 m_t << "</li>";
1049 if (!li.isPreformatted()) m_t << "\n";
1050}
1051
1052template<class Node>
1053static bool holds_value(const Node *val,const DocNodeVariant &v)
1054{
1055 bool b = std::visit([&](auto &&x) {
1056 //printf("holds_value val=%s (%p) v=%s (%p)\n",
1057 // docNodeName(*val),(void*)val,docNodeName(v),(void *)&x);
1058 return val==static_cast<const DocNode*>(&x);
1059 }, v);
1060 return b;
1061}
1062
1063template<class T>
1064bool isFirstChildNode(const T *parent, const DocPara &node)
1065{
1066 return !parent->children().empty() && holds_value(&node,parent->children().front());
1067}
1068
1069template<class T>
1070bool isLastChildNode(const T *parent, const DocPara &node)
1071{
1072 return !parent->children().empty() && holds_value(&node,parent->children().back());
1073}
1074
1076{
1077 const DocNodeList &nodes = parent.children();
1078 auto it = std::find_if(std::begin(nodes),std::end(nodes),[&par](const auto &n) { return holds_value(&par,n); });
1079 if (it==std::end(nodes)) return FALSE;
1080 size_t count = parent.children().size();
1081 auto isSeparator = [](auto &&it_) { return std::get_if<DocSimpleSectSep>(&(*it_))!=nullptr; };
1082 if (count>1 && it==std::begin(nodes)) // it points to first node
1083 {
1084 return isSeparator(std::next(it));
1085 }
1086 else if (count>1 && it==std::prev(std::end(nodes))) // it points to last node
1087 {
1088 return isSeparator(std::prev(it));
1089 }
1090 else if (count>2 && it!=std::begin(nodes) && it!=std::prev(std::end(nodes))) // it points to intermediate node
1091 {
1092 return isSeparator(std::prev(it)) && isSeparator(std::next(it));
1093 }
1094 return false;
1095}
1096
1097static contexts_t getParagraphContext(const DocPara &p,bool &isFirst,bool &isLast)
1098{
1100 isFirst=FALSE;
1101 isLast=FALSE;
1102 if (p.parent())
1103 {
1104 const auto parBlock = std::get_if<DocParBlock>(p.parent());
1105 if (parBlock)
1106 {
1107 // hierarchy: node N -> para -> parblock -> para
1108 // adapt return value to kind of N
1109 const DocNodeVariant *p3 = nullptr;
1110 if (::parent(p.parent()) && ::parent(::parent(p.parent())) )
1111 {
1112 p3 = ::parent(::parent(p.parent()));
1113 }
1114 isFirst=isFirstChildNode(parBlock,p);
1115 isLast =isLastChildNode (parBlock,p);
1116 bool isLI = p3!=nullptr && holds_one_of_alternatives<DocHtmlListItem,DocSecRefItem>(*p3);
1118 bool isTD = p3!=nullptr && holds_one_of_alternatives<DocHtmlCell,DocParamList>(*p3);
1120 if (isFirst)
1121 {
1122 if (isLI) t=contexts_t::STARTLI; else if (isDD) t=contexts_t::STARTDD; else if (isTD) t=contexts_t::STARTTD;
1123 }
1124 if (isLast)
1125 {
1126 if (isLI) t=contexts_t::ENDLI; else if (isDD) t=contexts_t::ENDDD; else if (isTD) t=contexts_t::ENDTD;
1127 }
1128 if (!isFirst && !isLast)
1129 {
1130 if (isLI) t=contexts_t::INTERLI; else if (isDD) t=contexts_t::INTERDD; else if (isTD) t=contexts_t::INTERTD;
1131 }
1132 return t;
1133 }
1134 const auto docAutoListItem = std::get_if<DocAutoListItem>(p.parent());
1135 if (docAutoListItem)
1136 {
1137 isFirst=isFirstChildNode(docAutoListItem,p);
1138 isLast =isLastChildNode (docAutoListItem,p);
1139 t=contexts_t::STARTLI; // not used
1140 return t;
1141 }
1142 const auto docSimpleListItem = std::get_if<DocSimpleListItem>(p.parent());
1143 if (docSimpleListItem)
1144 {
1145 isFirst=TRUE;
1146 isLast =TRUE;
1147 t=contexts_t::STARTLI; // not used
1148 return t;
1149 }
1150 const auto docParamList = std::get_if<DocParamList>(p.parent());
1151 if (docParamList)
1152 {
1153 isFirst=TRUE;
1154 isLast =TRUE;
1155 t=contexts_t::STARTLI; // not used
1156 return t;
1157 }
1158 const auto docHtmlListItem = std::get_if<DocHtmlListItem>(p.parent());
1159 if (docHtmlListItem)
1160 {
1161 isFirst=isFirstChildNode(docHtmlListItem,p);
1162 isLast =isLastChildNode (docHtmlListItem,p);
1163 if (isFirst) t=contexts_t::STARTLI;
1164 if (isLast) t=contexts_t::ENDLI;
1165 if (!isFirst && !isLast) t = contexts_t::INTERLI;
1166 return t;
1167 }
1168 const auto docSecRefItem = std::get_if<DocSecRefItem>(p.parent());
1169 if (docSecRefItem)
1170 {
1171 isFirst=isFirstChildNode(docSecRefItem,p);
1172 isLast =isLastChildNode (docSecRefItem,p);
1173 if (isFirst) t=contexts_t::STARTLI;
1174 if (isLast) t=contexts_t::ENDLI;
1175 if (!isFirst && !isLast) t = contexts_t::INTERLI;
1176 return t;
1177 }
1178 const auto docHtmlDescData = std::get_if<DocHtmlDescData>(p.parent());
1179 if (docHtmlDescData)
1180 {
1181 isFirst=isFirstChildNode(docHtmlDescData,p);
1182 isLast =isLastChildNode (docHtmlDescData,p);
1183 if (isFirst) t=contexts_t::STARTDD;
1184 if (isLast) t=contexts_t::ENDDD;
1185 if (!isFirst && !isLast) t = contexts_t::INTERDD;
1186 return t;
1187 }
1188 const auto docXRefItem = std::get_if<DocXRefItem>(p.parent());
1189 if (docXRefItem)
1190 {
1191 isFirst=isFirstChildNode(docXRefItem,p);
1192 isLast =isLastChildNode (docXRefItem,p);
1193 if (isFirst) t=contexts_t::STARTDD;
1194 if (isLast) t=contexts_t::ENDDD;
1195 if (!isFirst && !isLast) t = contexts_t::INTERDD;
1196 return t;
1197 }
1198 const auto docSimpleSect = std::get_if<DocSimpleSect>(p.parent());
1199 if (docSimpleSect)
1200 {
1201 isFirst=isFirstChildNode(docSimpleSect,p);
1202 isLast =isLastChildNode (docSimpleSect,p);
1203 if (isFirst) t=contexts_t::STARTDD;
1204 if (isLast) t=contexts_t::ENDDD;
1205 if (isSeparatedParagraph(*docSimpleSect,p))
1206 // if the paragraph is enclosed with separators it will
1207 // be included in <dd>..</dd> so avoid addition paragraph
1208 // markers
1209 {
1210 isFirst=isLast=TRUE;
1211 }
1212 if (!isFirst && !isLast) t = contexts_t::INTERDD;
1213 return t;
1214 }
1215 const auto docHtmlCell = std::get_if<DocHtmlCell>(p.parent());
1216 if (docHtmlCell)
1217 {
1218 isFirst=isFirstChildNode(docHtmlCell,p);
1219 isLast =isLastChildNode (docHtmlCell,p);
1220 if (isFirst) t=contexts_t::STARTTD;
1221 if (isLast) t=contexts_t::ENDTD;
1222 if (!isFirst && !isLast) t = contexts_t::INTERTD;
1223 return t;
1224 }
1225 }
1226 return t;
1227}
1228
1229static bool determineIfNeedsTag(const DocPara &p)
1230{
1231 bool needsTag = FALSE;
1232 if (p.parent())
1233 {
1247 >(*p.parent()))
1248 {
1249 needsTag = TRUE;
1250 }
1251 else if (std::get_if<DocRoot>(p.parent()))
1252 {
1253 needsTag = !std::get<DocRoot>(*p.parent()).singleLine();
1254 }
1255 }
1256 return needsTag;
1257}
1258
1260{
1261 if (m_hide) return;
1262
1263 //printf("> DocPara\n");
1264 //dumpDocNodeList(p.children());
1265
1266 bool needsTag = determineIfNeedsTag(p);
1267 //printf(" needsTag=%d\n",needsTag);
1268 bool needsTagBefore = needsTag;
1269 bool needsTagAfter = needsTag;
1270
1271 // if the first element of a paragraph is something that should be outside of
1272 // the paragraph (<ul>,<dl>,<table>,..) then that will already started the
1273 // paragraph and we don't need to do it here
1274 if (!p.children().empty())
1275 {
1276 auto it = std::find_if(std::begin(p.children()),std::end(p.children()),
1277 [](const auto &node) { return !isInvisibleNode(node); });
1278 if (it!=std::end(p.children()))
1279 {
1280 const DocNodeVariant &n = *it;
1282 {
1283 needsTagBefore = FALSE;
1284 }
1285 }
1286 }
1287
1288 // check if this paragraph is the first or last or intermediate child of a <li> or <dd>.
1289 // this allows us to mark the tag with a special class so we can
1290 // fix the otherwise ugly spacing.
1291 bool isFirst = false;
1292 bool isLast = false;
1293 contexts_t t = getParagraphContext(p,isFirst,isLast);
1294 //printf("startPara first=%d last=%d\n",isFirst,isLast);
1295 if (isFirst && isLast) needsTagBefore=FALSE;
1296
1297 //printf(" needsTagBefore=%d\n",needsTagBefore);
1298 // write the paragraph tag (if needed)
1299 if (needsTagBefore)
1300 {
1301 if (contexts(t))
1302 m_t << "<p class=\"" << contexts(t) << "\"" << p.attribs().toString() << ">";
1303 else
1304 m_t << "<p" << p.attribs().toString() << ">";
1305 }
1306
1307 visitChildren(p);
1308
1309 // if the last element of a paragraph is something that should be outside of
1310 // the paragraph (<ul>,<dl>,<table>) then that will already have ended the
1311 // paragraph and we don't need to do it here
1312 if (!p.children().empty())
1313 {
1314 auto it = std::prev(std::end(p.children()));
1315 for (;;)
1316 {
1317 const DocNodeVariant &n = *it;
1318 if (!isInvisibleNode(n))
1319 {
1321 {
1322 needsTagAfter = FALSE;
1323 }
1324 // stop searching if we found a node that is visible
1325 break;
1326 }
1327 if (it==std::begin(p.children()))
1328 {
1329 // stop searching if we are at the beginning of the list
1330 break;
1331 }
1332 else
1333 {
1334 --it;
1335 }
1336 }
1337 }
1338
1339 //printf("endPara first=%d last=%d\n",isFirst,isLast);
1340 if (isFirst && isLast) needsTagAfter=FALSE;
1341
1342 //printf(" needsTagAfter=%d\n",needsTagAfter);
1343 if (needsTagAfter) m_t << "</p>\n";
1344 //printf("< DocPara\n");
1345}
1346
1348{
1349 //printf("> DocRoot\n");
1350 //dumpDocNodeList(r.children());
1351 visitChildren(r);
1352 //printf("< DocRoot\n");
1353}
1354
1356{
1357 if (m_hide) return;
1359 m_t << "<dl class=\"section " << s.typeString() << "\"><dt>";
1360 switch(s.type())
1361 {
1362 case DocSimpleSect::See:
1363 m_t << theTranslator->trSeeAlso(); break;
1365 m_t << theTranslator->trReturns(); break;
1367 m_t << theTranslator->trAuthor(TRUE,TRUE); break;
1369 m_t << theTranslator->trAuthor(TRUE,FALSE); break;
1371 m_t << theTranslator->trVersion(); break;
1373 m_t << theTranslator->trSince(); break;
1375 m_t << theTranslator->trDate(); break;
1377 m_t << theTranslator->trNote(); break;
1379 m_t << theTranslator->trWarning(); break;
1380 case DocSimpleSect::Pre:
1381 m_t << theTranslator->trPrecondition(); break;
1383 m_t << theTranslator->trPostcondition(); break;
1385 m_t << theTranslator->trCopyright(); break;
1387 m_t << theTranslator->trInvariant(); break;
1389 m_t << theTranslator->trRemarks(); break;
1391 m_t << theTranslator->trAttention(); break;
1393 m_t << theTranslator->trImportant(); break;
1394 case DocSimpleSect::User: break;
1395 case DocSimpleSect::Rcs: break;
1396 case DocSimpleSect::Unknown: break;
1397 }
1398
1399 if (s.title())
1400 {
1401 std::visit(*this,*s.title());
1402 }
1403 m_t << "</dt><dd>";
1404 visitChildren(s);
1405 m_t << "</dd></dl>\n";
1407}
1408
1410{
1411 if (m_hide) return;
1412 visitChildren(t);
1413}
1414
1416{
1417 if (m_hide) return;
1419 m_t << "<ul>";
1420 if (!sl.isPreformatted()) m_t << "\n";
1421 visitChildren(sl);
1422 m_t << "</ul>";
1423 if (!sl.isPreformatted()) m_t << "\n";
1425}
1426
1428{
1429 if (m_hide) return;
1430 m_t << "<li>";
1431 if (li.paragraph())
1432 {
1433 visit(*this,*li.paragraph());
1434 }
1435 m_t << "</li>";
1436 if (!li.isPreformatted()) m_t << "\n";
1437}
1438
1440{
1441 if (m_hide) return;
1443 m_t << "<h" << s.level() << " class=\"doxsection\">";
1444 m_t << "<a class=\"anchor\" id=\"" << s.anchor();
1445 m_t << "\"></a>\n";
1446 if (s.title())
1447 {
1448 std::visit(*this,*s.title());
1449 }
1450 m_t << "</h" << s.level() << ">\n";
1451 visitChildren(s);
1453}
1454
1456{
1457 if (m_hide) return;
1459 if (s.type()==DocHtmlList::Ordered)
1460 {
1461 m_t << "<ol" << s.attribs().toString();
1462 }
1463 else
1464 {
1465 m_t << "<ul" << s.attribs().toString();
1466 }
1467 m_t << ">\n";
1468 visitChildren(s);
1469 if (s.type()==DocHtmlList::Ordered)
1470 {
1471 m_t << "</ol>";
1472 }
1473 else
1474 {
1475 m_t << "</ul>";
1476 }
1477 if (!s.isPreformatted()) m_t << "\n";
1479}
1480
1482{
1483 if (m_hide) return;
1484 m_t << "<li" << i.attribs().toString() << ">";
1485 if (!i.isPreformatted()) m_t << "\n";
1486 visitChildren(i);
1487 m_t << "</li>\n";
1488}
1489
1491{
1492 if (m_hide) return;
1494 m_t << "<dl" << dl.attribs().toString() << ">\n";
1495 visitChildren(dl);
1496 m_t << "</dl>\n";
1498}
1499
1501{
1502 if (m_hide) return;
1503 m_t << "<dt" << dt.attribs().toString() << ">";
1504 visitChildren(dt);
1505 m_t << "</dt>\n";
1506}
1507
1509{
1510 if (m_hide) return;
1511 m_t << "<dd" << dd.attribs().toString() << ">";
1512 visitChildren(dd);
1513 m_t << "</dd>\n";
1514}
1515
1517{
1518 if (m_hide) return;
1519
1521
1522 if (t.caption())
1523 {
1524 QCString anc = std::get<DocHtmlCaption>(*t.caption()).anchor();
1525 if (!anc.isEmpty())
1526 {
1527 m_t << "<a class=\"anchor\" id=\"" << anc << "\"></a>\n";
1528 }
1529 }
1530
1531 QCString attrs = t.attribs().toString();
1532 if (attrs.isEmpty())
1533 {
1534 m_t << "<table class=\"doxtable\">\n";
1535 }
1536 else
1537 {
1538 m_t << "<table" << t.attribs().toString() << ">\n";
1539 }
1540 if (t.caption())
1541 {
1542 std::visit(*this,*t.caption());
1543 }
1544 visitChildren(t);
1545 m_t << "</table>\n";
1547}
1548
1550{
1551 if (m_hide) return;
1552 m_t << "<tr" << tr.attribs().toString() << ">\n";
1553 visitChildren(tr);
1554 m_t << "</tr>\n";
1555}
1556
1558{
1559 if (m_hide) return;
1560 if (c.isHeading())
1561 {
1562 m_t << "<th" << c.attribs().toString() << ">";
1563 }
1564 else
1565 {
1566 m_t << "<td" << c.attribs().toString() << ">";
1567 }
1568 visitChildren(c);
1569 if (c.isHeading()) m_t << "</th>"; else m_t << "</td>";
1570}
1571
1573{
1574 if (m_hide) return;
1575 m_t << "<caption" << c.attribs().toString() << ">";
1576 visitChildren(c);
1577 m_t << "</caption>\n";
1578}
1579
1581{
1582 if (m_hide) return;
1583 visitChildren(i);
1584}
1585
1587{
1588 if (m_hide) return;
1589 if (href.url().startsWith("mailto:"))
1590 {
1592 }
1593 else
1594 {
1595 QCString url = correctURL(href.url(),href.relPath());
1596 m_t << "<a href=\"" << convertToHtml(url) << "\""
1597 << href.attribs().toString() << ">";
1598 }
1599 visitChildren(href);
1600 m_t << "</a>";
1601}
1602
1604{
1605 if (m_hide) return;
1606 m_t << "<summary " << s.attribs().toString() << ">\n";
1607 visitChildren(s);
1608 m_t << "</summary>\n";
1609}
1610
1612{
1613 if (m_hide) return;
1615 m_t << "<details " << d.attribs().toString() << ">\n";
1616 auto summary = d.summary();
1617 if (summary)
1618 {
1619 std::visit(*this,*summary);
1620 }
1621 visitChildren(d);
1622 m_t << "</details>\n";
1624}
1625
1627{
1628 if (m_hide) return;
1629 forceEndParagraph(header);
1630 m_t << "<h" << header.level() << header.attribs().toString() << ">";
1631 visitChildren(header);
1632 m_t << "</h" << header.level() << ">\n";
1633 forceStartParagraph(header);
1634}
1635
1637{
1638 if (img.type()==DocImage::Html)
1639 {
1640 bool inlineImage = img.isInlineImage();
1641 bool typeSVG = img.isSVG();
1642 QCString url = img.url();
1643
1644 if (!inlineImage)
1645 {
1646 forceEndParagraph(img);
1647 }
1648 if (m_hide) return;
1649 QCString baseName=stripPath(img.name());
1650 if (!inlineImage) m_t << "<div class=\"image\">\n";
1651 QCString sizeAttribs;
1652 if (!img.width().isEmpty())
1653 {
1654 sizeAttribs+=" width=\""+img.width()+"\"";
1655 }
1656 if (!img.height().isEmpty()) // link to local file
1657 {
1658 sizeAttribs+=" height=\""+img.height()+"\"";
1659 }
1660 // 16 cases: url.isEmpty() | typeSVG | inlineImage | img.hasCaption()
1661
1662 HtmlAttribList attribs = img.attribs();
1663 if (typeSVG)
1664 {
1665 attribs.mergeAttribute("style","pointer-events: none;");
1666 }
1667 QCString alt;
1668 QCString attrs = attribs.toString(&alt);
1669 QCString src;
1670 if (url.isEmpty())
1671 {
1672 src = img.relPath()+img.name();
1673 }
1674 else
1675 {
1676 src = correctURL(url,img.relPath());
1677 }
1678 if (typeSVG && !inlineImage && !src.startsWith("http://") && !src.startsWith("https://"))
1679 {
1680 m_t << "<object type=\"image/svg+xml\" data=\"" << convertToHtml(src)
1681 << "\"" << sizeAttribs << attrs;
1682 if (inlineImage)
1683 {
1684 // skip closing tag
1685 }
1686 else
1687 {
1688 m_t << ">" << alt << "</object>\n";
1689 }
1690 }
1691 else
1692 {
1693 m_t << "<img src=\"" << convertToHtml(src) << "\" alt=\"" << alt << "\"" << sizeAttribs << attrs;
1694 if (inlineImage)
1695 {
1696 m_t << " class=\"inline\"";
1697 }
1698 else
1699 {
1700 m_t << "/>\n";
1701 }
1702 }
1703 if (img.hasCaption())
1704 {
1705 if (inlineImage)
1706 {
1707 m_t << " title=\"";
1708 m_insideTitle=true;
1709 }
1710 else
1711 {
1712 m_t << "<div class=\"caption\">\n";
1713 }
1714 }
1715 else if (inlineImage)
1716 {
1717 m_t << "/>";
1718 }
1719
1720 visitChildren(img);
1721
1722 if (img.hasCaption())
1723 {
1724 if (inlineImage)
1725 {
1726 m_t << "\"/>";
1727 m_insideTitle=false;
1728 }
1729 else // end <div class="caption">
1730 {
1731 m_t << "</div>";
1732 }
1733 }
1734 if (!inlineImage) // end <div class="image">
1735 {
1736 m_t << "</div>\n";
1738 }
1739 }
1740 else // other format -> skip
1741 {
1742 }
1743}
1744
1746{
1747 if (m_hide) return;
1749 bool exists = false;
1750 std::string inBuf;
1751 if (readInputFile(df.file(),inBuf))
1752 {
1753 auto fileName = writeFileContents(Config_getString(HTML_OUTPUT)+"/"+stripPath(df.file())+"_", // baseName
1754 ".dot", // extension
1755 inBuf, // contents
1756 exists);
1757 if (!fileName.isEmpty())
1758 {
1759 m_t << "<div class=\"dotgraph\">\n";
1760 writeDotFile(fileName,df.relPath(),df.context(),df.srcFile(),df.srcLine(),!exists);
1761 if (df.hasCaption())
1762 {
1763 m_t << "<div class=\"caption\">\n";
1764 }
1765 visitChildren(df);
1766 if (df.hasCaption())
1767 {
1768 m_t << "</div>\n";
1769 }
1770 m_t << "</div>\n";
1771 }
1772 }
1774}
1775
1777{
1778 if (m_hide) return;
1780 bool exists = false;
1781 std::string inBuf;
1782 if (readInputFile(df.file(),inBuf))
1783 {
1784 auto fileName = writeFileContents(Config_getString(HTML_OUTPUT)+"/"+stripPath(df.file())+"_", // baseName
1785 ".msc", // extension
1786 inBuf, // contents
1787 exists);
1788 if (!fileName.isEmpty())
1789 {
1790 m_t << "<div class=\"mscgraph\">\n";
1791 writeMscFile(fileName,df.relPath(),df.context(),df.srcFile(),df.srcLine(),!exists);
1792 if (df.hasCaption())
1793 {
1794 m_t << "<div class=\"caption\">\n";
1795 }
1796 visitChildren(df);
1797 if (df.hasCaption())
1798 {
1799 m_t << "</div>\n";
1800 }
1801 m_t << "</div>\n";
1802 }
1803 }
1805}
1806
1808{
1809 if (m_hide) return;
1811 bool exists = false;
1812 std::string inBuf;
1813 if (readInputFile(df.file(),inBuf))
1814 {
1815 auto fileName = writeFileContents(Config_getString(HTML_OUTPUT)+"/"+stripPath(df.file())+"_", // baseName
1816 ".dia", // extension
1817 inBuf, // contents
1818 exists);
1819 if (!fileName.isEmpty())
1820 {
1821 m_t << "<div class=\"diagraph\">\n";
1822 writeDiaFile(fileName,df.relPath(),df.context(),df.srcFile(),df.srcLine(),!exists);
1823 if (df.hasCaption())
1824 {
1825 m_t << "<div class=\"caption\">\n";
1826 }
1827 visitChildren(df);
1828 if (df.hasCaption())
1829 {
1830 m_t << "</div>\n";
1831 }
1832 m_t << "</div>\n";
1833 }
1834 }
1836}
1837
1839{
1840 if (m_hide) return;
1841 if (!Config_getBool(DOT_CLEANUP)) copyFile(df.file(),Config_getString(HTML_OUTPUT)+"/"+stripPath(df.file()));
1843 QCString htmlOutput = Config_getString(HTML_OUTPUT);
1844 QCString imgExt = getDotImageExtension();
1845 PlantumlManager::OutputFormat format = PlantumlManager::PUML_BITMAP; // default : PUML_BITMAP
1846 if (imgExt=="svg")
1847 {
1849 }
1850 std::string inBuf;
1851 readInputFile(df.file(),inBuf);
1852 auto baseNameVector = PlantumlManager::instance().writePlantUMLSource(htmlOutput,QCString(),
1853 inBuf,format,QCString(),df.srcFile(),df.srcLine(),false);
1854 for (const auto &bName: baseNameVector)
1855 {
1856 QCString baseName=makeBaseName(bName,".pu");
1857 m_t << "<div class=\"plantumlgraph\">\n";
1858 writePlantUMLFile(baseName,df.relPath(),QCString(),df.srcFile(),df.srcLine());
1859 if (df.hasCaption())
1860 {
1861 m_t << "<div class=\"caption\">\n";
1862 }
1863 visitChildren(df);
1864 if (df.hasCaption())
1865 {
1866 m_t << "</div>\n";
1867 }
1868 m_t << "</div>\n";
1869 }
1871}
1872
1874{
1875 if (m_hide) return;
1876 if (!Config_getBool(DOT_CLEANUP)) copyFile(df.file(),Config_getString(HTML_OUTPUT)+"/"+stripPath(df.file()));
1878 if (Config_getEnum(MERMAID_RENDER_MODE)==MERMAID_RENDER_MODE_t::CLI)
1879 {
1880 std::string inBuf;
1881 readInputFile(df.file(),inBuf);
1882 auto htmlOutput = Config_getString(HTML_OUTPUT);
1883 auto outputFormat = MermaidManager::OutputFormat::HTML;
1884 auto imageFormat = MermaidManager::convertToImageFormat(outputFormat);
1886 inBuf,imageFormat,df.srcFile(),df.srcLine());
1887 m_t << "<div class=\"mermaidgraph\">\n";
1888 writeMermaidFile(baseName,df.relPath(),QCString(),df.srcFile(),df.srcLine());
1889 if (df.hasCaption())
1890 {
1891 m_t << "<div class=\"caption\">\n";
1892 }
1893 visitChildren(df);
1894 if (df.hasCaption())
1895 {
1896 m_t << "</div>\n";
1897 }
1898 m_t << "</div>\n";
1899 }
1900 else // AUTO or CLIENT_SIDE
1901 {
1902 // CLIENT_SIDE or AUTO: embed mermaid source for client-side rendering
1903 std::string inBuf;
1904 readInputFile(df.file(),inBuf);
1905 m_t << "<div class=\"mermaidgraph\">\n";
1906 m_t << "<pre class=\"mermaid\">\n";
1907 m_t << convertToHtml(inBuf);
1908 m_t << "</pre>\n";
1909 if (df.hasCaption())
1910 {
1911 m_t << "<div class=\"caption\">\n";
1912 }
1913 visitChildren(df);
1914 if (df.hasCaption())
1915 {
1916 m_t << "</div>\n";
1917 }
1918 m_t << "</div>\n";
1919 }
1921}
1922
1924{
1925 if (m_hide) return;
1926 startLink(lnk.ref(),lnk.file(),lnk.relPath(),lnk.anchor());
1927 visitChildren(lnk);
1928 endLink();
1929}
1930
1932{
1933 if (m_hide) return;
1934 if (!ref.file().isEmpty())
1935 {
1936 // when ref.isSubPage()==TRUE we use ref.file() for HTML and
1937 // ref.anchor() for LaTeX/RTF
1938 startLink(ref.ref(),ref.file(),ref.relPath(),ref.isSubPage() ? QCString() : ref.anchor(), ref.targetTitle());
1939 }
1940 if (!ref.hasLinkText()) filter(ref.targetTitle());
1941 visitChildren(ref);
1942 if (!ref.file().isEmpty()) endLink();
1943 //m_t << " ";
1944}
1945
1947{
1948 if (m_hide) return;
1949 if (!ref.file().isEmpty())
1950 {
1951 m_t << "<li>";
1952 startLink(ref.ref(),ref.file(),ref.relPath(),ref.isSubPage() ? QCString() : ref.anchor());
1953 }
1954 visitChildren(ref);
1955 if (!ref.file().isEmpty())
1956 {
1957 endLink();
1958 m_t << "</li>\n";
1959 }
1960}
1961
1963{
1964 if (m_hide) return;
1966 m_t << "<div>\n";
1967 m_t << "<ul class=\"multicol\">\n";
1968 visitChildren(s);
1969 m_t << "</ul>\n";
1970 m_t << "</div>\n";
1972}
1973
1975{
1976 if (m_hide) return;
1978 QCString className;
1979 QCString heading;
1980 switch(s.type())
1981 {
1983 heading=theTranslator->trParameters();
1984 className="params";
1985 break;
1987 heading=theTranslator->trReturnValues();
1988 className="retval";
1989 break;
1991 heading=theTranslator->trExceptions();
1992 className="exception";
1993 break;
1995 heading=theTranslator->trTemplateParameters();
1996 className="tparams";
1997 break;
1998 default:
1999 ASSERT(0);
2000 }
2001 m_t << "<dl class=\"" << className << "\"><dt>";
2002 m_t << heading;
2003 m_t << "</dt><dd>\n";
2004 m_t << " <table class=\"" << className << "\">\n";
2005 visitChildren(s);
2006 m_t << " </table>\n";
2007 m_t << " </dd>\n";
2008 m_t << "</dl>\n";
2010}
2011
2013{
2014 if (m_hide) return;
2015 m_t << "&#160;" << s.chars() << "&#160;";
2016}
2017
2019{
2020 //printf("DocParamList::visitPre\n");
2021 if (m_hide) return;
2022 m_t << " <tr>";
2023 const DocParamSect *sect = std::get_if<DocParamSect>(pl.parent());
2024 if (sect && sect->hasInOutSpecifier())
2025 {
2026 m_t << "<td class=\"paramdir\">";
2028 {
2029 m_t << "[";
2030 if (pl.direction()==DocParamSect::In)
2031 {
2032 m_t << "in";
2033 }
2034 else if (pl.direction()==DocParamSect::Out)
2035 {
2036 m_t << "out";
2037 }
2038 else if (pl.direction()==DocParamSect::InOut)
2039 {
2040 m_t << "in,out";
2041 }
2042 m_t << "]";
2043 }
2044 m_t << "</td>";
2045 }
2046 if (sect && sect->hasTypeSpecifier())
2047 {
2048 m_t << "<td class=\"paramtype\">";
2049 for (const auto &type : pl.paramTypes())
2050 {
2051 std::visit(*this,type);
2052 }
2053 m_t << "</td>";
2054 }
2055 m_t << "<td class=\"paramname\">";
2056 bool first=TRUE;
2057 for (const auto &param : pl.parameters())
2058 {
2059 if (!first) m_t << ","; else first=FALSE;
2060 std::visit(*this,param);
2061 }
2062 m_t << "</td><td>";
2063 for (const auto &par : pl.paragraphs())
2064 {
2065 std::visit(*this,par);
2066 }
2067 m_t << "</td></tr>\n";
2068}
2069
2071{
2072 if (m_hide) return;
2073 if (x.title().isEmpty()) return;
2074
2076 bool anonymousEnum = x.file()=="@";
2077 if (!anonymousEnum)
2078 {
2079 QCString fn = x.file();
2081 m_t << "<dl class=\"" << x.key() << "\"><dt><b><a class=\"el\" href=\""
2082 << x.relPath() << fn
2083 << "#" << x.anchor() << "\">";
2084 }
2085 else
2086 {
2087 m_t << "<dl class=\"" << x.key() << "\"><dt><b>";
2088 }
2089 filter(x.title());
2090 if (!anonymousEnum) m_t << "</a>";
2091 m_t << "</b></dt><dd>";
2092 visitChildren(x);
2093 if (x.title().isEmpty()) return;
2094 m_t << "</dd></dl>\n";
2096}
2097
2099{
2100 if (m_hide) return;
2101 startLink(QCString(),ref.file(),ref.relPath(),ref.anchor());
2102 visitChildren(ref);
2103 endLink();
2104 m_t << " ";
2105}
2106
2108{
2109 visitChildren(t);
2110}
2111
2113{
2114 if (m_hide) return;
2116 m_t << "<blockquote class=\"doxtable\"" << b.attribs().toString() << ">\n";
2117 visitChildren(b);
2118 m_t << "</blockquote>\n";
2120}
2121
2123{
2124 if (m_hide) return;
2125 if (VhdlDocGen::getFlowMember()) // use VHDL flow chart creator
2126 {
2129 m_t << "<p>";
2130 m_t << theTranslator->trFlowchart();
2131 m_t << " ";
2132 m_t << "<a href=\"";
2133 m_t << fname;
2134 m_t << ".svg\">";
2136 m_t << "</a>";
2137 if (vf.hasCaption())
2138 {
2139 m_t << "<br />";
2140 }
2141 }
2142 visitChildren(vf);
2143 if (VhdlDocGen::getFlowMember()) // use VHDL flow chart creator
2144 {
2145 m_t << "</p>";
2147 }
2148}
2149
2151{
2152 if (m_hide) return;
2153 visitChildren(pb);
2154}
2155
2156void HtmlDocVisitor::filter(const QCString &str, const bool retainNewline)
2157{
2158 if (str.isEmpty()) return;
2159 const char *p=str.data();
2160 while (*p)
2161 {
2162 char c=*p++;
2163 switch(c)
2164 {
2165 case '\n': if(retainNewline) m_t << "<br/>"; m_t << c; break;
2166 case '<': m_t << "&lt;"; break;
2167 case '>': m_t << "&gt;"; break;
2168 case '&': m_t << "&amp;"; break;
2169 case '\\':
2170 if ((*p == '(') || (*p == ')') || (*p == '[') || (*p == ']'))
2171 m_t << "\\&zwj;" << *p++;
2172 else
2173 m_t << c;
2174 break;
2175 default:
2176 {
2177 uint8_t uc = static_cast<uint8_t>(c);
2178 if (uc<32 && !isspace(c)) // non-printable control characters
2179 {
2180 m_t << "&#x24" << hex[uc>>4] << hex[uc&0xF] << ";";
2181 }
2182 else
2183 {
2184 m_t << c;
2185 }
2186 }
2187 break;
2188 }
2189 }
2190}
2191
2192/// Escape basic entities to produce a valid CDATA attribute value,
2193/// assume that the outer quoting will be using the double quote &quot;
2195{
2196 if (str.isEmpty()) return str;
2197 QCString result;
2198 result.reserve(str.length()+8);
2199 const char *p=str.data();
2200 while (*p)
2201 {
2202 char c=*p++;
2203 switch(c)
2204 {
2205 case '&': result+="&amp;"; break;
2206 case '"': result+="&quot;"; break;
2207 case '<': result+="&lt;"; break;
2208 case '>': result+="&gt;"; break;
2209 case '\\':
2210 if ((*p == '(') || (*p == ')') || (*p == '[') || (*p == ']'))
2211 {
2212 result+="\\&zwj;";
2213 result+=*p++;
2214 }
2215 else
2216 {
2217 result+=c;
2218 }
2219 break;
2220 default:
2221 {
2222 uint8_t uc = static_cast<uint8_t>(c);
2223 if (uc<32 && !isspace(c)) // non-printable control characters
2224 {
2225 result+="&#x24";
2226 result+=hex[uc>>4];
2227 result+=hex[uc&0xF];
2228 result+=";";
2229 }
2230 else
2231 {
2232 result+=c;
2233 }
2234 }
2235 break;
2236 }
2237 }
2238 return result;
2239}
2240
2241void HtmlDocVisitor::startLink(const QCString &ref,const QCString &file,
2242 const QCString &relPath,const QCString &anchor,
2243 const QCString &tooltip)
2244{
2245 //printf("HtmlDocVisitor: file=%s anchor=%s\n",qPrint(file),qPrint(anchor));
2246 if (!ref.isEmpty()) // link to entity imported via tag file
2247 {
2248 m_t << "<a class=\"elRef\" ";
2250 }
2251 else // local link
2252 {
2253 m_t << "<a class=\"el\" ";
2254 }
2255 m_t << "href=\"";
2256 QCString fn = file;
2258 m_t << createHtmlUrl(relPath,ref,true,
2259 m_fileName == Config_getString(HTML_OUTPUT)+"/"+fn,
2260 fn,
2261 anchor);
2262 m_t << "\"";
2263 if (!tooltip.isEmpty()) m_t << " title=\"" << convertToHtml(tooltip) << "\"";
2264 m_t << ">";
2265}
2266
2268{
2269 m_t << "</a>";
2270}
2271
2272void HtmlDocVisitor::writeDotFile(const QCString &fileName,const QCString &relPath,
2273 const QCString &context,const QCString &srcFile,int srcLine,bool newFile)
2274{
2275 QCString baseName=makeBaseName(fileName,".dot");
2276 baseName.prepend("dot_");
2277 QCString outDir = Config_getString(HTML_OUTPUT);
2278 if (newFile) writeDotGraphFromFile(fileName,outDir,baseName,GraphOutputFormat::BITMAP,srcFile,srcLine,true);
2279 writeDotImageMapFromFile(m_t,fileName,outDir,relPath,baseName,context,-1,srcFile,srcLine,newFile);
2280}
2281
2282void HtmlDocVisitor::writeMscFile(const QCString &fileName,const QCString &relPath,
2283 const QCString &context,const QCString &srcFile,int srcLine, bool newFile)
2284{
2285 QCString baseName=makeBaseName(fileName,".msc");
2286 baseName.prepend("msc_");
2287 QCString outDir = Config_getString(HTML_OUTPUT);
2288 QCString imgExt = getDotImageExtension();
2289 MscOutputFormat mscFormat = imgExt=="svg" ? MscOutputFormat::SVG : MscOutputFormat::BITMAP;
2290 if (newFile) writeMscGraphFromFile(fileName,outDir,baseName,mscFormat,srcFile,srcLine,true);
2291 writeMscImageMapFromFile(m_t,fileName,outDir,relPath,baseName,context,mscFormat,srcFile,srcLine);
2292}
2293
2294void HtmlDocVisitor::writeDiaFile(const QCString &fileName, const QCString &relPath,
2295 const QCString &,const QCString &srcFile,int srcLine, bool newFile)
2296{
2297 QCString baseName=makeBaseName(fileName,".dia");
2298 baseName.prepend("dia_");
2299 QCString outDir = Config_getString(HTML_OUTPUT);
2300 if (newFile) writeDiaGraphFromFile(fileName,outDir,baseName,DiaOutputFormat::BITMAP,srcFile,srcLine,true);
2301
2302 m_t << "<img src=\"" << relPath << baseName << ".png" << "\" />\n";
2303}
2304
2305void HtmlDocVisitor::writePlantUMLFile(const QCString &fileName, const QCString &relPath,
2306 const QCString &,const QCString &/* srcFile */,int /* srcLine */)
2307{
2308 QCString baseName=makeBaseName(fileName,".pu");
2309 QCString outDir = Config_getString(HTML_OUTPUT);
2310 QCString imgExt = getDotImageExtension();
2311 if (imgExt=="svg")
2312 {
2314 //m_t << "<iframe scrolling=\"no\" frameborder=\"0\" src=\"" << relPath << baseName << ".svg" << "\" />\n";
2315 //m_t << "<p><b>This browser is not able to show SVG: try Firefox, Chrome, Safari, or Opera instead.</b></p>";
2316 //m_t << "</iframe>\n";
2317 m_t << "<object type=\"image/svg+xml\" data=\"" << relPath << baseName << ".svg\"></object>\n";
2318 }
2319 else
2320 {
2322 m_t << "<img src=\"" << relPath << baseName << ".png" << "\" />\n";
2323 }
2324}
2325
2326void HtmlDocVisitor::writeMermaidFile(const QCString &fileName, const QCString &relPath,
2327 const QCString &,const QCString &/* srcFile */,int /* srcLine */)
2328{
2329 auto baseName = makeBaseName(fileName,".mmd");
2330 auto outDir = Config_getString(HTML_OUTPUT);
2331 auto outputFormat = MermaidManager::OutputFormat::HTML;
2332 auto imageFormat = MermaidManager::convertToImageFormat(outputFormat);
2333 auto imgExt = MermaidManager::imageExtension(imageFormat);
2334 MermaidManager::instance().generateMermaidOutput(fileName,outDir,imageFormat,true);
2335 if (imageFormat == MermaidManager::ImageFormat::SVG)
2336 {
2337 m_t << "<object type=\"image/svg+xml\" data=\"" << relPath << baseName << "." << imgExt << "\"></object>\n";
2338 }
2339 else
2340 {
2341 m_t << "<img src=\"" << relPath << baseName << "." << imgExt << "\" />\n";
2342 }
2343}
2344
2345/** Returns TRUE if the child nodes in paragraph \a para until \a nodeIndex
2346 contain a style change node that is still active and that style change is one that
2347 must be located outside of a paragraph, i.e. it is a center, div, or pre tag.
2348 See also bug746162.
2349 */
2352{
2353 //printf("insideStyleChangeThatIsOutputParagraph(index=%d)\n",nodeIndex);
2354 int styleMask=0;
2355 bool styleOutsideParagraph=FALSE;
2356 while (!styleOutsideParagraph)
2357 {
2358 const DocNodeVariant *n = &(*it);
2359 const DocStyleChange *sc = std::get_if<DocStyleChange>(n);
2360 if (sc)
2361 {
2362 if (!sc->enable()) // remember styles that has been closed already
2363 {
2364 styleMask|=static_cast<int>(sc->style());
2365 }
2366 bool paraStyle = sc->style()==DocStyleChange::Center ||
2367 sc->style()==DocStyleChange::Div ||
2369 //printf("Found style change %s enabled=%d\n",sc->styleString(),sc->enable());
2370 if (sc->enable() && (styleMask&static_cast<int>(sc->style()))==0 && // style change that is still active
2371 paraStyle
2372 )
2373 {
2374 styleOutsideParagraph=TRUE;
2375 }
2376 }
2377 if (it!=std::begin(para->children()))
2378 {
2379 --it;
2380 }
2381 else
2382 {
2383 break;
2384 }
2385 }
2386 return styleOutsideParagraph;
2387}
2388
2389/** Used for items found inside a paragraph, which due to XHTML restrictions
2390 * have to be outside of the paragraph. This method will forcefully end
2391 * the current paragraph and forceStartParagraph() will restart it.
2392 */
2393template<class Node>
2395{
2396 const DocPara *para=std::get_if<DocPara>(n.parent());
2397 if (para)
2398 {
2399 const DocNodeList &children = para->children();
2400
2401 //printf("forceEndParagraph\n");
2402 //dumpDocNodeList(children);
2403
2404 auto it = std::find_if(std::begin(children),std::end(children),
2405 [&n](const auto &np) { return holds_value(&n,np); });
2406 if (it==std::end(children)) return;
2407 if (it==std::begin(children)) return; // first node in paragraph
2408 it = std::prev(it);
2409 bool found=false;
2410 while (!found)
2411 {
2412 found = !isInvisibleNode(*it);
2413 if (found) break;
2414 if (it!=std::begin(children))
2415 {
2416 --it;
2417 }
2418 else
2419 {
2420 break;
2421 }
2422 }
2423 if (!found) return; // first visible node in paragraph
2424 const DocNodeVariant &v = *it;
2425 if (mustBeOutsideParagraph(v)) return; // previous node already outside paragraph context
2426 bool styleOutsideParagraph=false;
2427 if (it!=std::begin(children))
2428 {
2429 it = std::prev(it);
2430 styleOutsideParagraph=insideStyleChangeThatIsOutsideParagraph(para,it);
2431 }
2432 bool isFirst = false;
2433 bool isLast = false;
2434 getParagraphContext(*para,isFirst,isLast);
2435 //printf("forceEnd first=%d last=%d styleOutsideParagraph=%d\n",isFirst,isLast,styleOutsideParagraph);
2436 if (isFirst && isLast) return;
2437 if (styleOutsideParagraph) return;
2438
2439 //printf("adding </p>\n");
2440 m_t << "</p>";
2441 }
2442}
2443
2444/** Used for items found inside a paragraph, which due to XHTML restrictions
2445 * have to be outside of the paragraph. This method will forcefully start
2446 * the paragraph, that was previously ended by forceEndParagraph().
2447 */
2448template<class Node>
2450{
2451 //printf("> forceStartParagraph(%s)\n",docNodeName(n));
2452 const DocPara *para=nullptr;
2453 if (n.parent() && (para = std::get_if<DocPara>(n.parent()))) // if we are inside a paragraph
2454 {
2455 const DocNodeList &children = para->children();
2456
2457 auto it = std::find_if(std::begin(children),
2458 std::end(children),
2459 [&n](const auto &np)
2460 { return holds_value(&n,np); });
2461 if (it==std::end(children)) return;
2462 bool styleOutsideParagraph=insideStyleChangeThatIsOutsideParagraph(para,it);
2463 //printf("it=%s (%p) styleOutsideParagraph=%d\n",
2464 // docNodeName(*it), (void *)&*it, styleOutsideParagraph);
2465 if (styleOutsideParagraph) return;
2466 it = std::next(it);
2467 while (it!=std::end(children) && isInvisibleNode(*it))
2468 {
2469 ++it;
2470 }
2471 if (it!=std::end(children))
2472 {
2473 const DocNodeVariant &v = *it;
2474 if (mustBeOutsideParagraph(v)) return; // next element also outside paragraph
2475 }
2476 else
2477 {
2478 return; // only whitespace at the end!
2479 }
2480
2481 bool needsTag = true;
2482 bool isFirst = false;
2483 bool isLast = false;
2484 getParagraphContext(*para,isFirst,isLast);
2485 if (isFirst && isLast) needsTag = false;
2486 //printf("forceStart first=%d last=%d needsTag=%d\n",isFirst,isLast,needsTag);
2487
2488 if (needsTag) m_t << "<p>";
2489 }
2490}
2491
void parseCodeFragment(OutputCodeList &codeOutList, const QCString &fileName, const QCString &blockId, const QCString &scopeName, bool showLineNumbers, bool trimLeft, bool stripCodeComments)
static CodeFragmentManager & instance()
virtual void parseCode(OutputCodeList &codeOutList, const QCString &scopeName, const QCString &input, SrcLangExt lang, bool stripCodeComments, const CodeParserOptions &options)=0
Parses a source file or fragment with the goal to produce highlighted and cross-referenced output.
The common base class of all entity definitions found in the sources.
Definition definition.h:77
virtual QCString anchor() const =0
virtual QCString getDefFileExtension() const =0
virtual const QCString & name() const =0
Node representing an anchor.
Definition docnode.h:229
const HtmlAttribList & attribs() const
Definition docnode.h:235
QCString anchor() const
Definition docnode.h:232
Node representing an auto List.
Definition docnode.h:571
bool isCheckedList() const
Definition docnode.h:582
bool isEnumList() const
Definition docnode.h:580
int depth() const
Definition docnode.h:583
Node representing an item of a auto list.
Definition docnode.h:595
int itemNumber() const
Definition docnode.h:598
Node representing a citation of some bibliographic reference.
Definition docnode.h:245
QCString getText() const
Definition docnode.cpp:974
QCString relPath() const
Definition docnode.h:249
CiteInfoOption option() const
Definition docnode.h:253
QCString target() const
Definition docnode.h:252
QCString anchor() const
Definition docnode.h:251
QCString ref() const
Definition docnode.h:250
QCString file() const
Definition docnode.h:248
DocNodeList & children()
Definition docnode.h:143
Node representing a dia file.
Definition docnode.h:731
QCString relPath() const
Definition docnode.h:686
QCString srcFile() const
Definition docnode.h:691
QCString file() const
Definition docnode.h:685
int srcLine() const
Definition docnode.h:692
bool hasCaption() const
Definition docnode.h:687
QCString context() const
Definition docnode.h:690
Node representing a dot file.
Definition docnode.h:713
Node representing an emoji.
Definition docnode.h:341
int index() const
Definition docnode.h:345
QCString name() const
Definition docnode.h:344
Node representing an item of a cross-referenced list.
Definition docnode.h:529
QCString text() const
Definition docnode.h:533
QCString name() const
Definition docnode.h:532
bool isInline() const
Definition docnode.h:536
int id() const
Definition docnode.h:535
QCString relPath() const
Definition docnode.h:534
Node representing a Hypertext reference.
Definition docnode.h:832
QCString url() const
Definition docnode.h:839
QCString relPath() const
Definition docnode.h:841
const HtmlAttribList & attribs() const
Definition docnode.h:842
Node representing a horizontal ruler.
Definition docnode.h:216
const HtmlAttribList & attribs() const
Definition docnode.h:221
Node representing an HTML blockquote.
Definition docnode.h:1297
const HtmlAttribList & attribs() const
Definition docnode.h:1302
Node representing a HTML table caption.
Definition docnode.h:1234
const HtmlAttribList & attribs() const
Definition docnode.h:1237
Node representing a HTML table cell.
Definition docnode.h:1199
bool isHeading() const
Definition docnode.h:1206
const HtmlAttribList & attribs() const
Definition docnode.h:1211
Node representing a HTML description data.
Definition docnode.h:1187
const HtmlAttribList & attribs() const
Definition docnode.h:1190
Node representing a Html description list.
Definition docnode.h:910
const HtmlAttribList & attribs() const
Definition docnode.h:914
Node representing a Html description item.
Definition docnode.h:897
const HtmlAttribList & attribs() const
Definition docnode.h:901
Node Html details.
Definition docnode.h:866
const HtmlAttribList & attribs() const
Definition docnode.h:870
const DocNodeVariant * summary() const
Definition docnode.h:873
Node Html heading.
Definition docnode.h:882
const HtmlAttribList & attribs() const
Definition docnode.h:887
int level() const
Definition docnode.h:886
Node representing a Html list.
Definition docnode.h:1009
const HtmlAttribList & attribs() const
Definition docnode.h:1015
Type type() const
Definition docnode.h:1014
Node representing a HTML list item.
Definition docnode.h:1171
const HtmlAttribList & attribs() const
Definition docnode.h:1176
Node representing a HTML table row.
Definition docnode.h:1252
const HtmlAttribList & attribs() const
Definition docnode.h:1258
Node Html summary.
Definition docnode.h:853
const HtmlAttribList & attribs() const
Definition docnode.h:857
Node representing a HTML table.
Definition docnode.h:1275
const DocNodeVariant * caption() const
Definition docnode.cpp:2250
const HtmlAttribList & attribs() const
Definition docnode.h:1281
Node representing an image.
Definition docnode.h:642
const HtmlAttribList & attribs() const
Definition docnode.h:656
QCString relPath() const
Definition docnode.h:652
QCString name() const
Definition docnode.h:648
QCString url() const
Definition docnode.h:653
QCString height() const
Definition docnode.h:651
Type type() const
Definition docnode.h:647
QCString width() const
Definition docnode.h:650
bool isInlineImage() const
Definition docnode.h:654
bool isSVG() const
Definition docnode.cpp:1362
bool hasCaption() const
Definition docnode.h:649
Node representing a include/dontinclude operator block.
Definition docnode.h:477
bool stripCodeComments() const
Definition docnode.h:506
bool isLast() const
Definition docnode.h:503
QCString includeFileName() const
Definition docnode.h:509
QCString text() const
Definition docnode.h:499
QCString context() const
Definition docnode.h:501
QCString exampleFile() const
Definition docnode.h:508
int line() const
Definition docnode.h:497
Type type() const
Definition docnode.h:485
bool isFirst() const
Definition docnode.h:502
bool showLineNo() const
Definition docnode.h:498
bool isExample() const
Definition docnode.h:507
Node representing an included text block from file.
Definition docnode.h:435
QCString blockId() const
Definition docnode.h:454
QCString extension() const
Definition docnode.h:450
bool isBlock() const
Definition docnode.h:458
bool stripCodeComments() const
Definition docnode.h:455
@ LatexInclude
Definition docnode.h:437
@ SnippetWithLines
Definition docnode.h:438
@ DontIncWithLines
Definition docnode.h:439
@ IncWithLines
Definition docnode.h:438
@ HtmlInclude
Definition docnode.h:437
@ VerbInclude
Definition docnode.h:437
@ DontInclude
Definition docnode.h:437
@ DocbookInclude
Definition docnode.h:439
Type type() const
Definition docnode.h:451
QCString exampleFile() const
Definition docnode.h:457
QCString text() const
Definition docnode.h:452
QCString file() const
Definition docnode.h:449
bool trimLeft() const
Definition docnode.h:459
bool isExample() const
Definition docnode.h:456
QCString context() const
Definition docnode.h:453
Node representing an entry in the index.
Definition docnode.h:552
QCString entry() const
Definition docnode.h:559
const Definition * scope() const
Definition docnode.h:557
const MemberDef * member() const
Definition docnode.h:558
Node representing an internal section of documentation.
Definition docnode.h:978
Node representing an internal reference to some item.
Definition docnode.h:816
QCString file() const
Definition docnode.h:820
QCString relPath() const
Definition docnode.h:821
QCString anchor() const
Definition docnode.h:822
Node representing a line break.
Definition docnode.h:202
const HtmlAttribList & attribs() const
Definition docnode.h:208
Node representing a word that can be linked to something.
Definition docnode.h:165
QCString file() const
Definition docnode.h:171
QCString relPath() const
Definition docnode.h:172
QCString ref() const
Definition docnode.h:173
QCString word() const
Definition docnode.h:170
QCString anchor() const
Definition docnode.h:174
QCString tooltip() const
Definition docnode.h:175
Node representing a mermaid file.
Definition docnode.h:749
Node representing a msc file.
Definition docnode.h:722
Abstract node interface with type information.
Definition docnode.h:82
bool isPreformatted() const
Definition docnode.h:105
DocNodeVariant * parent()
Definition docnode.h:90
Node representing an block of paragraphs.
Definition docnode.h:988
Node representing a paragraph in the documentation tree.
Definition docnode.h:1089
const HtmlAttribList & attribs() const
Definition docnode.h:1120
Node representing a parameter list.
Definition docnode.h:1131
const DocNodeList & parameters() const
Definition docnode.h:1135
const DocNodeList & paramTypes() const
Definition docnode.h:1136
DocParamSect::Direction direction() const
Definition docnode.h:1139
const DocNodeList & paragraphs() const
Definition docnode.h:1137
Node representing a parameter section.
Definition docnode.h:1062
bool hasInOutSpecifier() const
Definition docnode.h:1078
bool hasTypeSpecifier() const
Definition docnode.h:1079
Type type() const
Definition docnode.h:1077
Node representing a uml file.
Definition docnode.h:740
Node representing a reference to some item.
Definition docnode.h:787
QCString anchor() const
Definition docnode.h:794
QCString relPath() const
Definition docnode.h:792
QCString targetTitle() const
Definition docnode.h:795
bool isSubPage() const
Definition docnode.h:801
QCString file() const
Definition docnode.h:791
QCString ref() const
Definition docnode.h:793
bool hasLinkText() const
Definition docnode.h:797
Root node of documentation tree.
Definition docnode.h:1319
Node representing a reference to a section.
Definition docnode.h:944
QCString relPath() const
Definition docnode.h:950
QCString file() const
Definition docnode.h:948
QCString anchor() const
Definition docnode.h:949
QCString ref() const
Definition docnode.h:951
bool isSubPage() const
Definition docnode.h:953
Node representing a list of section references.
Definition docnode.h:968
Node representing a normal section.
Definition docnode.h:923
int level() const
Definition docnode.h:927
QCString anchor() const
Definition docnode.h:929
const DocNodeVariant * title() const
Definition docnode.h:928
Node representing a separator.
Definition docnode.h:365
QCString chars() const
Definition docnode.h:369
Node representing a simple list.
Definition docnode.h:999
Node representing a simple list item.
Definition docnode.h:1159
const DocNodeVariant * paragraph() const
Definition docnode.h:1163
Node representing a simple section.
Definition docnode.h:1026
QCString typeString() const
Definition docnode.cpp:3260
Type type() const
Definition docnode.h:1035
const DocNodeVariant * title() const
Definition docnode.h:1042
Node representing a separator between two simple sections of the same type.
Definition docnode.h:1053
Node representing a style change.
Definition docnode.h:268
const HtmlAttribList & attribs() const
Definition docnode.h:311
QCString tagName() const
Definition docnode.h:312
Style style() const
Definition docnode.h:307
bool enable() const
Definition docnode.h:309
Node representing a special symbol.
Definition docnode.h:328
HtmlEntityMapper::SymType symbol() const
Definition docnode.h:332
Root node of a text fragment.
Definition docnode.h:1310
Node representing a simple section title.
Definition docnode.h:608
Node representing a URL (or email address).
Definition docnode.h:188
QCString url() const
Definition docnode.h:192
bool isEmail() const
Definition docnode.h:193
Node representing a verbatim, unparsed text fragment.
Definition docnode.h:376
QCString srcFile() const
Definition docnode.h:397
int srcLine() const
Definition docnode.h:398
QCString language() const
Definition docnode.h:388
bool isBlock() const
Definition docnode.h:389
bool isExample() const
Definition docnode.h:385
QCString context() const
Definition docnode.h:384
Type type() const
Definition docnode.h:382
QCString text() const
Definition docnode.h:383
QCString exampleFile() const
Definition docnode.h:386
QCString engine() const
Definition docnode.h:393
QCString relPath() const
Definition docnode.h:387
@ JavaDocLiteral
Definition docnode.h:378
Node representing a VHDL flow chart.
Definition docnode.h:758
bool hasCaption() const
Definition docnode.h:762
CodeParserInterface & getCodeParser(const QCString &langExt)
void pushHidden(bool hide)
bool popHidden()
Node representing some amount of white space.
Definition docnode.h:354
QCString chars() const
Definition docnode.h:358
Node representing a word.
Definition docnode.h:153
QCString word() const
Definition docnode.h:156
Node representing an item of a cross-referenced list.
Definition docnode.h:621
QCString anchor() const
Definition docnode.h:625
QCString key() const
Definition docnode.h:628
QCString relPath() const
Definition docnode.h:627
QCString file() const
Definition docnode.h:624
QCString title() const
Definition docnode.h:626
static IndexList * indexList
Definition doxygen.h:132
const char * unicode(int index) const
Access routine to the unicode sequence for the Emoji entity.
Definition emoji.cpp:2016
static EmojiEntityMapper & instance()
Returns the one and only instance of the Emoji entity mapper.
Definition emoji.cpp:1978
Minimal replacement for QFileInfo.
Definition fileinfo.h:23
std::string fileName() const
Definition fileinfo.cpp:118
std::string dirPath(bool absPath=true) const
Definition fileinfo.cpp:137
static QCString convertNameToFileName()
Class representing a LaTeX formula as found in the documentation.
Definition formula.h:29
int width() const
Definition formula.h:34
int height() const
Definition formula.h:35
const Formula * findFormula(int formulaId) const
Definition formula.cpp:705
static FormulaManager & instance()
Definition formula.cpp:53
Iterator< const GrowVector, const DocNodeVariant > const_iterator
Definition growvector.h:80
bool empty() const
checks whether the container is empty
Definition growvector.h:140
Class representing a list of HTML attributes.
Definition htmlattrib.h:33
QCString toString(QCString *pAltValue=nullptr) const
Definition htmlattrib.h:49
void mergeAttribute(const QCString &optName, const QCString &optValue)
Definition htmlattrib.h:35
HtmlDocVisitor(TextStream &t, OutputCodeList &ci, const Definition *ctx, const QCString &fn=QCString())
TextStream & m_t
void writeMscFile(const QCString &fileName, const QCString &relPath, const QCString &context, const QCString &srcFile, int srcLine, bool newFile=true)
void writePlantUMLFile(const QCString &fileName, const QCString &relPath, const QCString &context, const QCString &srcFile, int srcLine)
QCString filterQuotedCdataAttr(const QCString &str)
Escape basic entities to produce a valid CDATA attribute value, assume that the outer quoting will be...
void forceStartParagraph(const DocNode &n)
void operator()(const DocWord &)
void startLink(const QCString &ref, const QCString &file, const QCString &relPath, const QCString &anchor, const QCString &tooltip="")
void visitCaption(TextStream &t, const T &n)
OutputCodeList & m_ci
void writeDotFile(const QCString &fileName, const QCString &relPath, const QCString &context, const QCString &srcFile, int srcLine, bool newFile=true)
void visitChildren(const T &t)
void writeMermaidFile(const QCString &fileName, const QCString &relPath, const QCString &context, const QCString &srcFile, int srcLine)
void filter(const QCString &str, const bool retainNewline=false)
void forceEndParagraph(const DocNode &n)
void writeDiaFile(const QCString &fileName, const QCString &relPath, const QCString &context, const QCString &srcFile, int srcLine, bool newFile=true)
const Definition * m_ctx
void writeObfuscatedMailAddress(const QCString &url)
static HtmlEntityMapper & instance()
Returns the one and only instance of the HTML entity mapper.
const char * html(SymType symb, bool useInPrintf=FALSE) const
Access routine to the html code of the HTML entity.
void generateMermaidOutput(const QCString &baseName, const QCString &outDir, ImageFormat format, bool toIndex)
Register a generated Mermaid image with the index.
Definition mermaid.cpp:117
static QCString imageExtension(ImageFormat imageFormat)
Definition mermaid.cpp:43
static MermaidManager & instance()
Definition mermaid.cpp:33
static ImageFormat convertToImageFormat(OutputFormat outputFormat)
Definition mermaid.cpp:54
QCString writeMermaidSource(const QCString &outDirArg, const QCString &fileName, const QCString &content, ImageFormat format, const QCString &srcFile, int srcLine)
Write a Mermaid source file and register it for CLI rendering.
Definition mermaid.cpp:70
Class representing a list of different code generators.
Definition outputlist.h:165
OutputFormat
Plant UML output image formats.
Definition plantuml.h:44
void generatePlantUMLOutput(const QCString &baseName, const QCString &outDir, OutputFormat format, bool toIndex)
Convert a PlantUML file to an image.
Definition plantuml.cpp:202
StringVector writePlantUMLSource(const QCString &outDirArg, const QCString &fileName, const QCString &content, OutputFormat format, const QCString &engine, const QCString &srcFile, int srcLine, bool inlineCode)
Write a PlantUML compatible file.
Definition plantuml.cpp:31
static PlantumlManager & instance()
Definition plantuml.cpp:232
This is an alternative implementation of QCString.
Definition qcstring.h:101
QCString & prepend(const char *s)
Definition qcstring.h:422
size_t length() const
Returns the length of the string, not counting the 0-terminator.
Definition qcstring.h:166
bool startsWith(const char *s) const
Definition qcstring.h:507
QCString mid(size_t index, size_t len=static_cast< size_t >(-1)) const
Definition qcstring.h:241
char & at(size_t i)
Returns a reference to the character at index i.
Definition qcstring.h:593
bool isEmpty() const
Returns TRUE iff the string is empty.
Definition qcstring.h:163
const std::string & str() const
Definition qcstring.h:552
QCString & setNum(short n)
Definition qcstring.h:459
void reserve(size_t size)
Reserve space for size bytes without changing the string contents.
Definition qcstring.h:185
const char * data() const
Returns a pointer to the contents of the string in the form of a 0-terminated C string.
Definition qcstring.h:172
Text streaming class that buffers data.
Definition textstream.h:36
std::string str() const
Return the contents of the buffer as a std::string object.
Definition textstream.h:216
static const MemberDef * getFlowMember()
#define Config_getBool(name)
Definition config.h:33
#define Config_getString(name)
Definition config.h:32
#define Config_getEnum(name)
Definition config.h:35
void writeDiaGraphFromFile(const QCString &inFile, const QCString &outDir, const QCString &outFile, DiaOutputFormat format, const QCString &srcFile, int srcLine, bool toIndex)
Definition dia.cpp:28
static constexpr auto hex
constexpr bool holds_one_of_alternatives(const DocNodeVariant &v)
returns true iff v holds one of types passed as template parameters
Definition docnode.h:1372
std::variant< DocWord, DocLinkedWord, DocURL, DocLineBreak, DocHorRuler, DocAnchor, DocCite, DocStyleChange, DocSymbol, DocEmoji, DocWhiteSpace, DocSeparator, DocVerbatim, DocInclude, DocIncOperator, DocFormula, DocIndexEntry, DocAutoList, DocAutoListItem, DocTitle, DocXRefItem, DocImage, DocDotFile, DocMscFile, DocDiaFile, DocVhdlFlow, DocLink, DocRef, DocInternalRef, DocHRef, DocHtmlHeader, DocHtmlDescTitle, DocHtmlDescList, DocSection, DocSecRefItem, DocSecRefList, DocInternal, DocParBlock, DocSimpleList, DocHtmlList, DocSimpleSect, DocSimpleSectSep, DocParamSect, DocPara, DocParamList, DocSimpleListItem, DocHtmlListItem, DocHtmlDescData, DocHtmlCell, DocHtmlCaption, DocHtmlRow, DocHtmlTable, DocHtmlBlockQuote, DocText, DocRoot, DocHtmlDetails, DocHtmlSummary, DocPlantUmlFile, DocMermaidFile > DocNodeVariant
Definition docnode.h:67
constexpr DocNodeVariant * parent(DocNodeVariant *n)
returns the parent node of a given node n or nullptr if the node has no parent.
Definition docnode.h:1336
void writeDotGraphFromFile(const QCString &inFile, const QCString &outDir, const QCString &outFile, GraphOutputFormat format, const QCString &srcFile, int srcLine, bool toIndex)
Definition dot.cpp:196
void writeDotImageMapFromFile(TextStream &t, const QCString &inFile, const QCString &outDir, const QCString &relPath, const QCString &baseName, const QCString &context, int graphId, const QCString &srcFile, int srcLine, bool newFile)
Definition dot.cpp:249
std::unique_ptr< FileDef > createFileDef(const QCString &p, const QCString &n, const QCString &ref, const QCString &dn)
Definition filedef.cpp:268
static bool isInvisibleNode(const DocNodeVariant &node)
static bool determineIfNeedsTag(const DocPara &p)
static const char g_types[][NUM_HTML_LIST_TYPES]
static constexpr const char * contexts(contexts_t type)
contexts_t
bool isFirstChildNode(const T *parent, const DocPara &node)
static const int NUM_HTML_LIST_TYPES
static QCString convertIndexWordToAnchor(const QCString &word)
static contexts_t getParagraphContext(const DocPara &p, bool &isFirst, bool &isLast)
static bool mustBeOutsideParagraph(const DocNodeVariant &n)
static bool isDocVerbatimVisible(const DocVerbatim &s)
static bool insideStyleChangeThatIsOutsideParagraph(const DocPara *para, DocNodeList::const_iterator it)
Returns TRUE if the child nodes in paragraph para until nodeIndex contain a style change node that is...
static bool holds_value(const Node *val, const DocNodeVariant &v)
static bool isDocIncOperatorVisible(const DocIncOperator &s)
bool isSeparatedParagraph(const DocSimpleSect &parent, const DocPara &par)
bool isLastChildNode(const T *parent, const DocPara &node)
static bool isDocIncludeVisible(const DocInclude &s)
Translator * theTranslator
Definition language.cpp:71
#define err(fmt,...)
Definition message.h:127
void writeMscImageMapFromFile(TextStream &t, const QCString &inFile, const QCString &outDir, const QCString &relPath, const QCString &baseName, const QCString &context, MscOutputFormat format, const QCString &srcFile, int srcLine)
Definition msc.cpp:233
void writeMscGraphFromFile(const QCString &inFile, const QCString &outDir, const QCString &outFile, MscOutputFormat format, const QCString &srcFile, int srcLine, bool toIndex)
Definition msc.cpp:157
MscOutputFormat
Definition msc.h:22
Portable versions of functions that are platform dependent.
#define TRUE
Definition qcstring.h:37
#define FALSE
Definition qcstring.h:34
#define ASSERT(x)
Definition qcstring.h:39
Options to configure the code parser.
Definition parserintf.h:78
CodeParserOptions & setSearchCtx(const Definition *d)
Definition parserintf.h:116
CodeParserOptions & setStartLine(int lineNr)
Definition parserintf.h:101
CodeParserOptions & setInlineFragment(bool enable)
Definition parserintf.h:107
CodeParserOptions & setShowLineNumbers(bool enable)
Definition parserintf.h:113
CodeParserOptions & setFileDef(const FileDef *fd)
Definition parserintf.h:98
SrcLangExt
Definition types.h:207
const char * writeUTF8Char(TextStream &t, const char *s)
Writes the UTF8 character pointed to by s to stream t and returns a pointer to the next character.
Definition utf8.cpp:197
QCString writeFileContents(const QCString &baseName, const QCString &extension, const QCString &content, bool &exists)
Thread-safe function to write a string to a file.
Definition util.cpp:6977
SrcLangExt getLanguageFromFileName(const QCString &fileName, SrcLangExt defLang)
Definition util.cpp:5231
QCString convertToHtml(const QCString &s, bool keepEntities)
Definition util.cpp:3984
QCString correctURL(const QCString &url, const QCString &relPath)
Corrects URL url according to the relative path relPath.
Definition util.cpp:5943
QCString stripPath(const QCString &s)
Definition util.cpp:4969
bool readInputFile(const QCString &fileName, std::string &contents, bool filter, bool isSourceCode)
read a file name fileName and optionally filter and transcode it
Definition util.cpp:5570
SrcLangExt getLanguageFromCodeLang(QCString &fileName)
Routine to handle the language attribute of the \code command.
Definition util.cpp:5249
QCString getDotImageExtension()
Definition util.cpp:6307
QCString makeBaseName(const QCString &name, const QCString &ext)
Definition util.cpp:4985
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:5875
QCString externalLinkTarget(const bool parent)
Definition util.cpp:5745
QCString getFileNameExtension(const QCString &fn)
Definition util.cpp:5273
void addHtmlExtensionIfMissing(QCString &fName)
Definition util.cpp:4942
QCString createHtmlUrl(const QCString &relPath, const QCString &ref, bool href, bool isLocalFile, const QCString &targetFileName, const QCString &anchor)
Definition util.cpp:5756
A bunch of utility functions.