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 "formula.h"
37#include "fileinfo.h"
38#include "indexlist.h"
39#include "growbuf.h"
40#include "portable.h"
41#include "codefragment.h"
42
43static const int NUM_HTML_LIST_TYPES = 4;
44static const char g_types[][NUM_HTML_LIST_TYPES] = {"1", "a", "i", "A"};
45enum class contexts_t
46{
47 NONE, // 0
48 STARTLI, // 1
49 STARTDD, // 2
50 ENDLI, // 3
51 ENDDD, // 4
52 STARTTD, // 5
53 ENDTD, // 6
54 INTERLI, // 7
55 INTERDD, // 8
57};
58
59static constexpr const char *contexts(contexts_t type)
60{
61 switch (type)
62 {
63 case contexts_t::NONE: return nullptr;
64 case contexts_t::STARTLI: return "startli";
65 case contexts_t::STARTDD: return "startdd";
66 case contexts_t::ENDLI: return "endli";
67 case contexts_t::ENDDD: return "enddd";
68 case contexts_t::STARTTD: return "starttd";
69 case contexts_t::ENDTD: return "endtd";
70 case contexts_t::INTERLI: return "interli";
71 case contexts_t::INTERDD: return "interdd";
72 case contexts_t::INTERTD: return "intertd";
73 default: return nullptr;
74 }
75}
76static const char *hex="0123456789ABCDEF";
77
79{
80 static int cnt = 0;
81 QCString result="a";
82 QCString cntStr;
83 result += cntStr.setNum(cnt);
84 result += "_";
85 cnt++;
86 const char *str = word.data();
87 unsigned char c = 0;
88 if (str)
89 {
90 while ((c = *str++))
91 {
92 if ((c >= 'a' && c <= 'z') || // ALPHA
93 (c >= 'A' && c <= 'Z') || // ALPHA
94 (c >= '0' && c <= '9') || // DIGIT
95 c == '-' ||
96 c == '.'
97 )
98 {
99 result += c;
100 }
101 else
102 {
103 char enc[4];
104 enc[0] = '_';
105 enc[1] = hex[(c & 0xf0) >> 4];
106 enc[2] = hex[c & 0xf];
107 enc[3] = 0;
108 result += enc;
109 }
110 }
111 }
112 return result;
113}
114
115
116
118{
119 //printf("mustBeOutsideParagraph(%s)=",docNodeName(n));
122 /* <table> */ DocHtmlTable,
123 /* <h?> */ DocSection, DocHtmlHeader,
124 /* \internal */ DocInternal,
125 /* <div> */ DocInclude, DocSecRefList,
126 /* <hr> */ DocHorRuler,
127 /* <blockquote> */ DocHtmlBlockQuote,
128 /* \parblock */ DocParBlock,
129 /* \dotfile */ DocDotFile,
130 /* \mscfile */ DocMscFile,
131 /* \diafile */ DocDiaFile,
132 /* \plantumlfile */ DocPlantUmlFile,
133 /* <details> */ DocHtmlDetails,
134 /* <summary> */ DocHtmlSummary,
135 DocIncOperator >(n))
136 {
137 return TRUE;
138 }
139 const DocVerbatim *dv = std::get_if<DocVerbatim>(&n);
140 if (dv)
141 {
142 DocVerbatim::Type t = dv->type();
144 return t!=DocVerbatim::HtmlOnly || dv->isBlock();
145 }
146 const DocStyleChange *sc = std::get_if<DocStyleChange>(&n);
147 if (sc)
148 {
149 return sc->style()==DocStyleChange::Preformatted ||
150 sc->style()==DocStyleChange::Div ||
152 }
153 const DocFormula *df = std::get_if<DocFormula>(&n);
154 if (df)
155 {
156 return !df->isInline();
157 }
158 const DocImage *di = std::get_if<DocImage>(&n);
159 if (di)
160 {
161 return !di->isInlineImage();
162 }
163 return FALSE;
164}
165
167{
168 switch (s.type())
169 {
175 return FALSE;
176 default:
177 return TRUE;
178 }
179}
180
181static bool isDocIncludeVisible(const DocInclude &s)
182{
183 switch (s.type())
184 {
191 return FALSE;
192 default:
193 return TRUE;
194 }
195}
196
198{
199 switch (s.type())
200 {
202 return FALSE;
203 default:
204 return TRUE;
205 }
206}
207
208static bool isInvisibleNode(const DocNodeVariant &node)
209{
210 //printf("isInvisibleNode(%s)\n",docNodeName(node));
211 // skip over white space
212 const DocWhiteSpace *ws = std::get_if<DocWhiteSpace>(&node);
213 if (ws) return true;
214 // skip over image nodes that are not for HTML output
215 const DocImage *di = std::get_if<DocImage>(&node);
216 if (di) return di->type()!=DocImage::Html;
217 // skip over verbatim nodes that are not visible in the HTML output
218 const DocVerbatim *dv = std::get_if<DocVerbatim>(&node);
219 if (dv) return !isDocVerbatimVisible(*dv);
220 // skip over include nodes that are not visible in the HTML output
221 const DocInclude *dinc = std::get_if<DocInclude>(&node);
222 if (dinc) return !isDocIncludeVisible(*dinc);
223 const DocIncOperator *dio = std::get_if<DocIncOperator>(&node);
224 // skip over include operator nodes that are not visible in the HTML output
225 if (dio) return !isDocIncOperatorVisible(*dio);
226 return false;
227}
228
229static QCString makeShortName(const QCString &name)
230{
231 QCString shortName = name;
232 int i = shortName.findRev('/');
233 if (i!=-1)
234 {
235 shortName=shortName.mid(i+1);
236 }
237 return shortName;
238}
239
240static QCString makeBaseName(const QCString &name)
241{
242 QCString baseName = makeShortName(name);
243 int i=baseName.find('.');
244 if (i!=-1)
245 {
246 baseName=baseName.left(i);
247 }
248 return baseName;
249}
250
251
252//-------------------------------------------------------------------------
253
255 const Definition *ctx,const QCString &fn)
256 : m_t(t), m_ci(ci), m_ctx(ctx), m_fileName(fn)
257{
258 if (ctx) m_langExt=ctx->getDefFileExtension();
259}
260
261template<class T>
263{
264 if (n.hasCaption())
265 {
266 t << "<div class=\"caption\">\n";
267 for (const auto &child : n.children())
268 {
269 std::visit(*this, child);
270 }
271 t << "</div>\n";
272 }
273}
274
275 //--------------------------------------
276 // visitor functions for leaf nodes
277 //--------------------------------------
278
280{
281 if (m_hide) return;
282 filter(w.word());
283}
284
286{
287 if (m_hide) return;
288 //printf("linked word: %s\n",qPrint(w.word()));
289 startLink(w.ref(),w.file(),w.relPath(),w.anchor(),w.tooltip());
290 filter(w.word());
291 endLink();
292}
293
295{
296 if (m_hide) return;
297 if (m_insidePre)
298 {
299 m_t << w.chars();
300 }
301 else
302 {
303 m_t << " ";
304 }
305}
306
308{
309 if (m_hide) return;
310 if (m_insideTitle &&
311 (s.symbol()==HtmlEntityMapper::Sym_Quot || s.symbol()==HtmlEntityMapper::Sym_quot)) // escape "'s inside title="..."
312 {
313 m_t << "&quot;";
314 }
315 else
316 {
317 const char *res = HtmlEntityMapper::instance().html(s.symbol());
318 if (res)
319 {
320 m_t << res;
321 }
322 else
323 {
324 err("HTML: non supported HTML-entity found: {}\n",
326 }
327 }
328}
329
331{
332 if (m_hide) return;
333 const char *res = EmojiEntityMapper::instance().unicode(s.index());
334 if (res)
335 {
336 m_t << "<span class=\"emoji\">" << res << "</span>";
337 }
338 else
339 {
340 m_t << s.name();
341 }
342}
343
345{
346 if (!Config_getBool(OBFUSCATE_EMAILS))
347 {
348 m_t << "<a href=\"mailto:" << url << "\">";
349 }
350 else
351 {
352 m_t << "<a href=\"#\" onclick=\"location.href='mai'+'lto:'";
353 if (!url.isEmpty())
354 {
355 const char *p = url.data();
356 uint32_t size=3;
357 while (*p)
358 {
359 m_t << "+'";
360 for (uint32_t j=0;j<size && *p;j++)
361 {
362 p = writeUTF8Char(m_t,p);
363 }
364 m_t << "'";
365 if (size==3) size=2; else size=3;
366 }
367 }
368 m_t << "; return false;\">";
369 }
370}
371
373{
374 if (m_hide) return;
375 if (u.isEmail()) // mail address
376 {
377 QCString url = u.url();
378 // obfuscate the mail address link
380 if (!Config_getBool(OBFUSCATE_EMAILS))
381 {
382 m_t << url;
383 }
384 else
385 {
386 const char *p = url.data();
387 // also obfuscate the address as shown on the web page
388 uint32_t size=5;
389 while (*p)
390 {
391 for (uint32_t j=0;j<size && *p;j++)
392 {
393 p = writeUTF8Char(m_t,p);
394 }
395 if (*p) m_t << "<span class=\"obfuscator\">.nosp@m.</span>";
396 if (size==5) size=4; else size=5;
397 }
398 }
399 m_t << "</a>";
400 }
401 else // web address
402 {
403 m_t << "<a href=\"";
404 filter(u.url());
405 m_t << "\">";
406 filter(u.url());
407 m_t << "</a>";
408 }
409}
410
412{
413 if (m_hide) return;
414 m_t << "<br "<< br.attribs().toString() << " />\n";
415}
416
418{
419 if (m_hide) return;
421 m_t << "<hr "<< hr.attribs().toString() << " />\n";
423}
424
426{
427 if (m_hide) return;
428 switch (s.style())
429 {
431 if (s.enable()) m_t << "<b" << s.attribs().toString() << ">"; else m_t << "</b>";
432 break;
434 if (s.enable()) m_t << "<s" << s.attribs().toString() << ">"; else m_t << "</s>";
435 break;
437 if (s.enable()) m_t << "<strike" << s.attribs().toString() << ">"; else m_t << "</strike>";
438 break;
440 if (s.enable()) m_t << "<del" << s.attribs().toString() << ">"; else m_t << "</del>";
441 break;
443 if (s.enable()) m_t << "<u" << s.attribs().toString() << ">"; else m_t << "</u>";
444 break;
446 if (s.enable()) m_t << "<ins" << s.attribs().toString() << ">"; else m_t << "</ins>";
447 break;
449 if (s.enable())
450 {
451 auto attribs = s.attribs();
452 if (s.tagName()=="a")
453 {
454 attribs.mergeAttribute("class","arg");
455 }
456 m_t << "<em" << attribs.toString() << ">";
457 }
458 else
459 {
460 m_t << "</em>";
461 }
462 break;
464 if (s.enable()) m_t << "<kbd" << s.attribs().toString() << ">"; else m_t << "</kbd>";
465 break;
467 if (s.enable())
468 {
469 m_t << "<span class=\"tt\"" << s.attribs().toString() << ">";
470 m_insidePre=true;
471 }
472 else
473 {
474 m_t << "</span>";
475 m_insidePre=false;
476 }
477 break;
479 if (s.enable())
480 {
481 auto attribs = s.attribs();
482 if (s.tagName()=="p")
483 {
484 attribs.mergeAttribute("class","param");
485 }
486 m_t << "<code" << attribs.toString() << ">";
487 m_insidePre=true;
488 }
489 else
490 {
491 m_insidePre=false;
492 m_t << "</code>";
493 }
494 break;
496 if (s.enable()) m_t << "<sub" << s.attribs().toString() << ">"; else m_t << "</sub>";
497 break;
499 if (s.enable()) m_t << "<sup" << s.attribs().toString() << ">"; else m_t << "</sup>";
500 break;
502 if (s.enable())
503 {
505 m_t << "<center" << s.attribs().toString() << ">";
506 }
507 else
508 {
509 m_t << "</center>";
511 }
512 break;
514 if (s.enable()) m_t << "<small" << s.attribs().toString() << ">"; else m_t << "</small>";
515 break;
517 if (s.enable()) m_t << "<cite" << s.attribs().toString() << ">"; else m_t << "</cite>";
518 break;
520 if (s.enable())
521 {
523 m_t << "<pre" << s.attribs().toString() << ">";
525 }
526 else
527 {
529 m_t << "</pre>";
531 }
532 break;
534 if (s.enable())
535 {
537 m_t << "<div" << s.attribs().toString() << ">";
538 }
539 else
540 {
541 m_t << "</div>";
543 }
544 break;
546 if (s.enable()) m_t << "<span" << s.attribs().toString() << ">"; else m_t << "</span>";
547 break;
548 }
549}
550
551///--------------------------------------------------------------------------------------
552
554{
555 if (m_hide) return;
556 QCString lang = m_langExt;
557 if (!s.language().isEmpty()) // explicit language setting
558 {
559 lang = s.language();
560 }
561 SrcLangExt langExt = getLanguageFromCodeLang(lang);
562 switch(s.type())
563 {
566 m_ci.startCodeFragment("DoxyCode");
568 s.context(),
569 s.text(),
570 langExt,
571 Config_getBool(STRIP_CODE_COMMENTS),
572 s.isExample(),
573 s.exampleFile(),
574 nullptr, // fileDef
575 -1, // startLine
576 -1, // endLine
577 true, // inlineFragment
578 nullptr, // memberDef
579 true, // show line numbers
580 m_ctx // search context
581 );
582 m_ci.endCodeFragment("DoxyCode");
584 break;
587 m_t << "<pre class=\"fragment\">";
588 filter(s.text());
589 m_t << "</pre>";
591 break;
593 filter(s.text(), true);
594 break;
596 m_t << "<code class=\"JavaDocCode\">";
597 filter(s.text(), true);
598 m_t << "</code>";
599 break;
601 {
602 if (s.isBlock()) forceEndParagraph(s);
603 m_t << s.text();
604 if (s.isBlock()) forceStartParagraph(s);
605 }
606 break;
612 /* nothing */
613 break;
614
615 case DocVerbatim::Dot:
616 {
617 static int dotindex = 1;
618 QCString fileName(4096, QCString::ExplicitSize);
619
621 fileName.sprintf("%s%d%s",
622 qPrint(Config_getString(HTML_OUTPUT)+"/inline_dotgraph_"),
623 dotindex++,
624 ".dot"
625 );
626 std::ofstream file = Portable::openOutputStream(fileName);
627 if (!file.is_open())
628 {
629 err("Could not open file {} for writing\n",fileName);
630 }
631 else
632 {
633 QCString stext = s.text();
634 file.write( stext.data(), stext.length() );
635 file.close();
636
637 m_t << "<div class=\"dotgraph\">\n";
638 writeDotFile(fileName,s.relPath(),s.context(),s.srcFile(),s.srcLine());
639 visitCaption(m_t, s);
640 m_t << "</div>\n";
641
642 if (Config_getBool(DOT_CLEANUP)) Dir().remove(fileName.str());
643 }
645 }
646 break;
647 case DocVerbatim::Msc:
648 {
650
651 static int mscindex = 1;
652 QCString baseName(4096, QCString::ExplicitSize);
653
654 baseName.sprintf("%s%d",
655 qPrint(Config_getString(HTML_OUTPUT)+"/inline_mscgraph_"),
656 mscindex++
657 );
658 std::ofstream file = Portable::openOutputStream(baseName.str()+".msc");
659 if (!file.is_open())
660 {
661 err("Could not open file {}.msc for writing\n",baseName);
662 }
663 else
664 {
665 QCString text = "msc {";
666 text+=s.text();
667 text+="}";
668
669 file.write( text.data(), text.length() );
670 file.close();
671
672 m_t << "<div class=\"mscgraph\">\n";
673 writeMscFile(baseName+".msc",s.relPath(),s.context(),s.srcFile(),s.srcLine());
674 visitCaption(m_t, s);
675 m_t << "</div>\n";
676
677 if (Config_getBool(DOT_CLEANUP)) Dir().remove(baseName.str()+".msc");
678 }
680 }
681 break;
683 {
685 QCString htmlOutput = Config_getString(HTML_OUTPUT);
687 PlantumlManager::OutputFormat format = PlantumlManager::PUML_BITMAP; // default : PUML_BITMAP
688 if (imgExt=="svg")
689 {
691 }
693 htmlOutput,s.exampleFile(),
694 s.text(),format,s.engine(),s.srcFile(),s.srcLine(),true);
695 m_t << "<div class=\"plantumlgraph\">\n";
696 writePlantUMLFile(baseName,s.relPath(),s.context(),s.srcFile(),s.srcLine());
697 visitCaption(m_t, s);
698 m_t << "</div>\n";
700 }
701 break;
702 }
703}
704
706{
707 if (m_hide) return;
708 m_t << "<a class=\"anchor\" id=\"" << anc.anchor() << "\"" << anc.attribs().toString() << "></a>";
709}
710
712{
713 if (m_hide) return;
715 switch(inc.type())
716 {
719 m_ci.startCodeFragment("DoxyCode");
721 inc.context(),
722 inc.text(),
723 langExt,
724 inc.stripCodeComments(),
725 inc.isExample(),
726 inc.exampleFile(),
727 nullptr, // fileDef
728 -1, // startLine
729 -1, // endLine
730 TRUE, // inlineFragment
731 nullptr, // memberDef
732 FALSE, // show line numbers
733 m_ctx // search context
734 );
735 m_ci.endCodeFragment("DoxyCode");
737 break;
739 {
741 m_ci.startCodeFragment("DoxyCode");
742 FileInfo cfi( inc.file().str() );
743 auto fd = createFileDef( cfi.dirPath(), cfi.fileName() );
745 inc.context(),
746 inc.text(),
747 langExt,
748 inc.stripCodeComments(),
749 inc.isExample(),
750 inc.exampleFile(),
751 fd.get(), // fileDef,
752 -1, // start line
753 -1, // end line
754 true, // inline fragment
755 nullptr, // memberDef
756 true, // show line numbers
757 m_ctx // search context
758 );
759 m_ci.endCodeFragment("DoxyCode");
761 }
762 break;
770 break;
772 {
773 if (inc.isBlock()) forceEndParagraph(inc);
774 m_t << inc.text();
775 if (inc.isBlock()) forceStartParagraph(inc);
776 }
777 break;
780 m_t << "<pre class=\"fragment\">";
781 filter(inc.text());
782 m_t << "</pre>";
784 break;
788 m_ci.startCodeFragment("DoxyCode");
790 inc.file(),
791 inc.blockId(),
792 inc.context(),
794 inc.trimLeft(),
796 );
797 m_ci.endCodeFragment("DoxyCode");
799 break;
800 }
801}
802
804{
805 //printf("DocIncOperator: type=%d first=%d, last=%d text='%s'\n",
806 // op.type(),op.isFirst(),op.isLast(),qPrint(op.text()));
807 if (op.isFirst())
808 {
810 if (!m_hide) m_ci.startCodeFragment("DoxyCode");
812 m_hide=TRUE;
813 }
815 if (locLangExt.isEmpty()) locLangExt = m_langExt;
816 SrcLangExt langExt = getLanguageFromFileName(locLangExt);
817 if (op.type()!=DocIncOperator::Skip)
818 {
819 m_hide = popHidden();
820 if (!m_hide)
821 {
822 std::unique_ptr<FileDef> fd;
823 if (!op.includeFileName().isEmpty())
824 {
825 FileInfo cfi( op.includeFileName().str() );
826 fd = createFileDef( cfi.dirPath(), cfi.fileName() );
827 }
828 getCodeParser(locLangExt).parseCode(
829 m_ci,
830 op.context(),
831 op.text(),
832 langExt,
834 op.isExample(),
835 op.exampleFile(),
836 fd.get(), // fileDef
837 op.line(), // startLine
838 -1, // endLine
839 true, // inline fragment
840 nullptr, // memberDef
841 op.showLineNo(), // show line numbers
842 m_ctx // search context
843 );
844 }
846 m_hide=TRUE;
847 }
848 if (op.isLast())
849 {
850 m_hide = popHidden();
851 if (!m_hide) m_ci.endCodeFragment("DoxyCode");
853 }
854 else
855 {
856 if (!m_hide) m_t << "\n";
857 }
858}
859
861{
862 if (m_hide) return;
863 bool bDisplay = !f.isInline();
864 if (bDisplay)
865 {
867 m_t << "<p class=\"formulaDsp\">\n";
868 }
869
870 if (Config_getBool(USE_MATHJAX))
871 {
872 QCString text = f.text();
873 bool closeInline = FALSE;
874 if (!bDisplay && !text.isEmpty() && text.at(0)=='$' &&
875 text.at(text.length()-1)=='$')
876 {
877 closeInline=TRUE;
878 text = text.mid(1,text.length()-2);
879 m_t << "\\(";
880 }
881 else if (!bDisplay && !text.isEmpty())
882 {
883 closeInline=TRUE;
884 m_t << "\\(";
885 }
886 m_t << convertToHtml(text);
887 if (closeInline)
888 {
889 m_t << "\\)";
890 }
891 }
892 else
893 {
894 const Formula *formula = FormulaManager::instance().findFormula(f.id());
895
896 enum class ImageType { Light, Dark };
897 enum class Visibility { Always, Dark, Light, AutoDark, AutoLight };
898 auto writeFormula = [&](ImageType imgType,Visibility visibility) -> QCString {
899 // see https://chipcullen.com/how-to-have-dark-mode-image-that-works-with-user-choice for the design idea
900 TextStream t;
901 QCString extension = Config_getEnum(HTML_FORMULA_FORMAT)==HTML_FORMULA_FORMAT_t::svg ? ".svg":".png" ;
902 if (visibility==Visibility::AutoDark || visibility==Visibility::AutoLight)
903 {
904 t << "<picture>";
905 t << "<source srcset=\"" << f.relPath() << f.name();
906 if (visibility==Visibility::AutoDark)
907 {
908 t << extension;
909 t << "\" media=\"(prefers-color-scheme: light)\"";
910 }
911 else // AutoLight
912 {
913 t << "_dark";
914 t << extension;
915 t << "\" media=\"(prefers-color-scheme: dark)\"";
916 }
917 t << "/>";
918 }
919 t << "<img class=\"formula";
920 t << (bDisplay ? "Dsp" : "Inl");
921 if (visibility==Visibility::Light) t << " light-mode-visible";
922 else if (visibility==Visibility::Dark) t << " dark-mode-visible";
923 t << "\" alt=\"" << filterQuotedCdataAttr(f.text()) << "\"" << " src=\"" << f.relPath() << f.name();
924 if (imgType==ImageType::Dark) t << "_dark";
925 t << extension;
926 if (formula && formula->width()!=-1)
927 {
928 t << "\" width=\"";
929 t << formula->width();
930 }
931 if (formula && formula->height()!=-1)
932 {
933 t << "\" height=\"";
934 t << formula->height();
935 }
936 t << "\"/>";
937 if (visibility==Visibility::AutoDark || visibility==Visibility::AutoLight)
938 {
939 t << "</picture>";
940 }
941 return QCString(t.str());
942 };
943
944 auto colorStyle = Config_getEnum(HTML_COLORSTYLE);
945 switch(colorStyle)
946 {
947 case HTML_COLORSTYLE_t::LIGHT:
948 m_t << writeFormula(ImageType::Light,Visibility::Always);
949 break;
950 case HTML_COLORSTYLE_t::DARK:
951 m_t << writeFormula(ImageType::Dark, Visibility::Always);
952 break;
953 case HTML_COLORSTYLE_t::AUTO_LIGHT:
954 m_t << writeFormula(ImageType::Light, Visibility::AutoLight);
955 break;
956 case HTML_COLORSTYLE_t::AUTO_DARK:
957 m_t << writeFormula(ImageType::Dark, Visibility::AutoDark);
958 break;
959 case HTML_COLORSTYLE_t::TOGGLE:
960 // write the image twice and use javascript (darkmode_toggle.js) to show only one of them
961 m_t << writeFormula(ImageType::Light,Visibility::Light);
962 m_t << writeFormula(ImageType::Dark, Visibility::Dark);
963 break;
964 }
965 }
966 if (bDisplay)
967 {
968 m_t << "\n</p>\n";
970 }
971}
972
974{
976 if (e.member())
977 {
978 anchor.prepend(e.member()->anchor()+"_");
979 }
980 m_t << "<a id=\"" << anchor << "\" name=\"" << anchor << "\"></a>";
981 //printf("*** DocIndexEntry: word='%s' scope='%s' member='%s'\n",
982 // qPrint(e.entry()),
983 // e.scope() ? qPrint(e.scope()->name()) : "<null>",
984 // e.member() ? qPrint(e.member()->name()) : "<null>"
985 // );
986 Doxygen::indexList->addIndexItem(e.scope(),e.member(),anchor,e.entry());
987}
988
990{
991 m_t << "</dd>\n";
992 m_t << "<dd>\n";
993}
994
996{
997 if (m_hide) return;
998 if (!cite.file().isEmpty())
999 {
1000 startLink(cite.ref(),cite.file(),cite.relPath(),cite.anchor());
1001 }
1002 else
1003 {
1004 m_t << "<b>[";
1005 }
1006 filter(cite.text());
1007 if (!cite.file().isEmpty())
1008 {
1009 endLink();
1010 }
1011 else
1012 {
1013 m_t << "]</b>";
1014 }
1015}
1016
1017
1018//--------------------------------------
1019// visitor functions for compound nodes
1020//--------------------------------------
1021
1022
1024{
1025 //printf("DocAutoList::visitPre\n");
1026 if (m_hide) return;
1028 if (l.isEnumList())
1029 {
1030 //
1031 // Do list type based on depth:
1032 // 1.
1033 // a.
1034 // i.
1035 // A.
1036 // 1. (repeat)...
1037 //
1038 m_t << "<ol type=\"" << g_types[l.depth() % NUM_HTML_LIST_TYPES] << "\">";
1039 }
1040 else
1041 {
1042 if (l.isCheckedList())
1043 {
1044 m_t << "<ul class=\"check\">";
1045 }
1046 else
1047 {
1048 m_t << "<ul>";
1049 }
1050 }
1051 if (!l.isPreformatted()) m_t << "\n";
1052 visitChildren(l);
1053 if (l.isEnumList())
1054 {
1055 m_t << "</ol>";
1056 }
1057 else
1058 {
1059 m_t << "</ul>";
1060 }
1061 if (!l.isPreformatted()) m_t << "\n";
1063}
1064
1066{
1067 if (m_hide) return;
1068 switch (li.itemNumber())
1069 {
1070 case DocAutoList::Unchecked: // unchecked
1071 m_t << "<li class=\"unchecked\">";
1072 break;
1073 case DocAutoList::Checked_x: // checked with x
1074 case DocAutoList::Checked_X: // checked with X
1075 m_t << "<li class=\"checked\">";
1076 break;
1077 default:
1078 m_t << "<li>";
1079 break;
1080 }
1081 visitChildren(li);
1082 m_t << "</li>";
1083 if (!li.isPreformatted()) m_t << "\n";
1084}
1085
1086template<class Node>
1087static bool holds_value(const Node *val,const DocNodeVariant &v)
1088{
1089 bool b = std::visit([&](auto &&x) {
1090 //printf("holds_value val=%s (%p) v=%s (%p)\n",
1091 // docNodeName(*val),(void*)val,docNodeName(v),(void *)&x);
1092 return val==static_cast<const DocNode*>(&x);
1093 }, v);
1094 return b;
1095}
1096
1097template<class T>
1098bool isFirstChildNode(const T *parent, const DocPara &node)
1099{
1100 return !parent->children().empty() && holds_value(&node,parent->children().front());
1101}
1102
1103template<class T>
1104bool isLastChildNode(const T *parent, const DocPara &node)
1105{
1106 return !parent->children().empty() && holds_value(&node,parent->children().back());
1107}
1108
1110{
1111 const DocNodeList &nodes = parent.children();
1112 auto it = std::find_if(std::begin(nodes),std::end(nodes),[&par](const auto &n) { return holds_value(&par,n); });
1113 if (it==std::end(nodes)) return FALSE;
1114 size_t count = parent.children().size();
1115 auto isSeparator = [](auto &&it_) { return std::get_if<DocSimpleSectSep>(&(*it_))!=nullptr; };
1116 if (count>1 && it==std::begin(nodes)) // it points to first node
1117 {
1118 return isSeparator(std::next(it));
1119 }
1120 else if (count>1 && it==std::prev(std::end(nodes))) // it points to last node
1121 {
1122 return isSeparator(std::prev(it));
1123 }
1124 else if (count>2 && it!=std::begin(nodes) && it!=std::prev(std::end(nodes))) // it points to intermediate node
1125 {
1126 return isSeparator(std::prev(it)) && isSeparator(std::next(it));
1127 }
1128 return false;
1129}
1130
1131static contexts_t getParagraphContext(const DocPara &p,bool &isFirst,bool &isLast)
1132{
1134 isFirst=FALSE;
1135 isLast=FALSE;
1136 if (p.parent())
1137 {
1138 const auto parBlock = std::get_if<DocParBlock>(p.parent());
1139 if (parBlock)
1140 {
1141 // hierarchy: node N -> para -> parblock -> para
1142 // adapt return value to kind of N
1143 const DocNodeVariant *p3 = nullptr;
1144 if (::parent(p.parent()) && ::parent(::parent(p.parent())) )
1145 {
1146 p3 = ::parent(::parent(p.parent()));
1147 }
1148 isFirst=isFirstChildNode(parBlock,p);
1149 isLast =isLastChildNode (parBlock,p);
1150 bool isLI = p3!=nullptr && holds_one_of_alternatives<DocHtmlListItem,DocSecRefItem>(*p3);
1152 bool isTD = p3!=nullptr && holds_one_of_alternatives<DocHtmlCell,DocParamList>(*p3);
1154 if (isFirst)
1155 {
1156 if (isLI) t=contexts_t::STARTLI; else if (isDD) t=contexts_t::STARTDD; else if (isTD) t=contexts_t::STARTTD;
1157 }
1158 if (isLast)
1159 {
1160 if (isLI) t=contexts_t::ENDLI; else if (isDD) t=contexts_t::ENDDD; else if (isTD) t=contexts_t::ENDTD;
1161 }
1162 if (!isFirst && !isLast)
1163 {
1164 if (isLI) t=contexts_t::INTERLI; else if (isDD) t=contexts_t::INTERDD; else if (isTD) t=contexts_t::INTERTD;
1165 }
1166 return t;
1167 }
1168 const auto docAutoListItem = std::get_if<DocAutoListItem>(p.parent());
1169 if (docAutoListItem)
1170 {
1171 isFirst=isFirstChildNode(docAutoListItem,p);
1172 isLast =isLastChildNode (docAutoListItem,p);
1173 t=contexts_t::STARTLI; // not used
1174 return t;
1175 }
1176 const auto docSimpleListItem = std::get_if<DocSimpleListItem>(p.parent());
1177 if (docSimpleListItem)
1178 {
1179 isFirst=TRUE;
1180 isLast =TRUE;
1181 t=contexts_t::STARTLI; // not used
1182 return t;
1183 }
1184 const auto docParamList = std::get_if<DocParamList>(p.parent());
1185 if (docParamList)
1186 {
1187 isFirst=TRUE;
1188 isLast =TRUE;
1189 t=contexts_t::STARTLI; // not used
1190 return t;
1191 }
1192 const auto docHtmlListItem = std::get_if<DocHtmlListItem>(p.parent());
1193 if (docHtmlListItem)
1194 {
1195 isFirst=isFirstChildNode(docHtmlListItem,p);
1196 isLast =isLastChildNode (docHtmlListItem,p);
1197 if (isFirst) t=contexts_t::STARTLI;
1198 if (isLast) t=contexts_t::ENDLI;
1199 if (!isFirst && !isLast) t = contexts_t::INTERLI;
1200 return t;
1201 }
1202 const auto docSecRefItem = std::get_if<DocSecRefItem>(p.parent());
1203 if (docSecRefItem)
1204 {
1205 isFirst=isFirstChildNode(docSecRefItem,p);
1206 isLast =isLastChildNode (docSecRefItem,p);
1207 if (isFirst) t=contexts_t::STARTLI;
1208 if (isLast) t=contexts_t::ENDLI;
1209 if (!isFirst && !isLast) t = contexts_t::INTERLI;
1210 return t;
1211 }
1212 const auto docHtmlDescData = std::get_if<DocHtmlDescData>(p.parent());
1213 if (docHtmlDescData)
1214 {
1215 isFirst=isFirstChildNode(docHtmlDescData,p);
1216 isLast =isLastChildNode (docHtmlDescData,p);
1217 if (isFirst) t=contexts_t::STARTDD;
1218 if (isLast) t=contexts_t::ENDDD;
1219 if (!isFirst && !isLast) t = contexts_t::INTERDD;
1220 return t;
1221 }
1222 const auto docXRefItem = std::get_if<DocXRefItem>(p.parent());
1223 if (docXRefItem)
1224 {
1225 isFirst=isFirstChildNode(docXRefItem,p);
1226 isLast =isLastChildNode (docXRefItem,p);
1227 if (isFirst) t=contexts_t::STARTDD;
1228 if (isLast) t=contexts_t::ENDDD;
1229 if (!isFirst && !isLast) t = contexts_t::INTERDD;
1230 return t;
1231 }
1232 const auto docSimpleSect = std::get_if<DocSimpleSect>(p.parent());
1233 if (docSimpleSect)
1234 {
1235 isFirst=isFirstChildNode(docSimpleSect,p);
1236 isLast =isLastChildNode (docSimpleSect,p);
1237 if (isFirst) t=contexts_t::STARTDD;
1238 if (isLast) t=contexts_t::ENDDD;
1239 if (isSeparatedParagraph(*docSimpleSect,p))
1240 // if the paragraph is enclosed with separators it will
1241 // be included in <dd>..</dd> so avoid addition paragraph
1242 // markers
1243 {
1244 isFirst=isLast=TRUE;
1245 }
1246 if (!isFirst && !isLast) t = contexts_t::INTERDD;
1247 return t;
1248 }
1249 const auto docHtmlCell = std::get_if<DocHtmlCell>(p.parent());
1250 if (docHtmlCell)
1251 {
1252 isFirst=isFirstChildNode(docHtmlCell,p);
1253 isLast =isLastChildNode (docHtmlCell,p);
1254 if (isFirst) t=contexts_t::STARTTD;
1255 if (isLast) t=contexts_t::ENDTD;
1256 if (!isFirst && !isLast) t = contexts_t::INTERTD;
1257 return t;
1258 }
1259 }
1260 return t;
1261}
1262
1263static bool determineIfNeedsTag(const DocPara &p)
1264{
1265 bool needsTag = FALSE;
1266 if (p.parent())
1267 {
1281 >(*p.parent()))
1282 {
1283 needsTag = TRUE;
1284 }
1285 else if (std::get_if<DocRoot>(p.parent()))
1286 {
1287 needsTag = !std::get<DocRoot>(*p.parent()).singleLine();
1288 }
1289 }
1290 return needsTag;
1291}
1292
1294{
1295 if (m_hide) return;
1296
1297 //printf("> DocPara\n");
1298 //dumpDocNodeList(p.children());
1299
1300 bool needsTag = determineIfNeedsTag(p);
1301 //printf(" needsTag=%d\n",needsTag);
1302 bool needsTagBefore = needsTag;
1303 bool needsTagAfter = needsTag;
1304
1305 // if the first element of a paragraph is something that should be outside of
1306 // the paragraph (<ul>,<dl>,<table>,..) then that will already started the
1307 // paragraph and we don't need to do it here
1308 if (!p.children().empty())
1309 {
1310 auto it = std::find_if(std::begin(p.children()),std::end(p.children()),
1311 [](const auto &node) { return !isInvisibleNode(node); });
1312 if (it!=std::end(p.children()))
1313 {
1314 const DocNodeVariant &n = *it;
1316 {
1317 needsTagBefore = FALSE;
1318 }
1319 }
1320 }
1321
1322 // check if this paragraph is the first or last or intermediate child of a <li> or <dd>.
1323 // this allows us to mark the tag with a special class so we can
1324 // fix the otherwise ugly spacing.
1325 bool isFirst = false;
1326 bool isLast = false;
1327 contexts_t t = getParagraphContext(p,isFirst,isLast);
1328 //printf("startPara first=%d last=%d\n",isFirst,isLast);
1329 if (isFirst && isLast) needsTagBefore=FALSE;
1330
1331 //printf(" needsTagBefore=%d\n",needsTagBefore);
1332 // write the paragraph tag (if needed)
1333 if (needsTagBefore)
1334 {
1335 if (contexts(t))
1336 m_t << "<p class=\"" << contexts(t) << "\"" << p.attribs().toString() << ">";
1337 else
1338 m_t << "<p" << p.attribs().toString() << ">";
1339 }
1340
1341 visitChildren(p);
1342
1343 // if the last element of a paragraph is something that should be outside of
1344 // the paragraph (<ul>,<dl>,<table>) then that will already have ended the
1345 // paragraph and we don't need to do it here
1346 if (!p.children().empty())
1347 {
1348 auto it = std::prev(std::end(p.children()));
1349 for (;;)
1350 {
1351 const DocNodeVariant &n = *it;
1352 if (!isInvisibleNode(n))
1353 {
1355 {
1356 needsTagAfter = FALSE;
1357 }
1358 // stop searching if we found a node that is visible
1359 break;
1360 }
1361 if (it==std::begin(p.children()))
1362 {
1363 // stop searching if we are at the beginning of the list
1364 break;
1365 }
1366 else
1367 {
1368 --it;
1369 }
1370 }
1371 }
1372
1373 //printf("endPara first=%d last=%d\n",isFirst,isLast);
1374 if (isFirst && isLast) needsTagAfter=FALSE;
1375
1376 //printf(" needsTagAfter=%d\n",needsTagAfter);
1377 if (needsTagAfter) m_t << "</p>\n";
1378 //printf("< DocPara\n");
1379}
1380
1382{
1383 //printf("> DocRoot\n");
1384 //dumpDocNodeList(r.children());
1385 visitChildren(r);
1386 //printf("< DocRoot\n");
1387}
1388
1390{
1391 if (m_hide) return;
1393 m_t << "<dl class=\"section " << s.typeString() << "\"><dt>";
1394 switch(s.type())
1395 {
1396 case DocSimpleSect::See:
1397 m_t << theTranslator->trSeeAlso(); break;
1399 m_t << theTranslator->trReturns(); break;
1401 m_t << theTranslator->trAuthor(TRUE,TRUE); break;
1403 m_t << theTranslator->trAuthor(TRUE,FALSE); break;
1405 m_t << theTranslator->trVersion(); break;
1407 m_t << theTranslator->trSince(); break;
1409 m_t << theTranslator->trDate(); break;
1411 m_t << theTranslator->trNote(); break;
1413 m_t << theTranslator->trWarning(); break;
1414 case DocSimpleSect::Pre:
1415 m_t << theTranslator->trPrecondition(); break;
1417 m_t << theTranslator->trPostcondition(); break;
1419 m_t << theTranslator->trCopyright(); break;
1421 m_t << theTranslator->trInvariant(); break;
1423 m_t << theTranslator->trRemarks(); break;
1425 m_t << theTranslator->trAttention(); break;
1427 m_t << theTranslator->trImportant(); break;
1428 case DocSimpleSect::User: break;
1429 case DocSimpleSect::Rcs: break;
1430 case DocSimpleSect::Unknown: break;
1431 }
1432
1433 if (s.title())
1434 {
1435 std::visit(*this,*s.title());
1436 }
1437 m_t << "</dt><dd>";
1438 visitChildren(s);
1439 m_t << "</dd></dl>\n";
1441}
1442
1444{
1445 if (m_hide) return;
1446 visitChildren(t);
1447}
1448
1450{
1451 if (m_hide) return;
1453 m_t << "<ul>";
1454 if (!sl.isPreformatted()) m_t << "\n";
1455 visitChildren(sl);
1456 m_t << "</ul>";
1457 if (!sl.isPreformatted()) m_t << "\n";
1459}
1460
1462{
1463 if (m_hide) return;
1464 m_t << "<li>";
1465 if (li.paragraph())
1466 {
1467 visit(*this,*li.paragraph());
1468 }
1469 m_t << "</li>";
1470 if (!li.isPreformatted()) m_t << "\n";
1471}
1472
1474{
1475 if (m_hide) return;
1477 m_t << "<h" << s.level() << " class=\"doxsection\">";
1478 m_t << "<a class=\"anchor\" id=\"" << s.anchor();
1479 m_t << "\"></a>\n";
1480 if (s.title())
1481 {
1482 std::visit(*this,*s.title());
1483 }
1484 m_t << "</h" << s.level() << ">\n";
1485 visitChildren(s);
1487}
1488
1490{
1491 if (m_hide) return;
1493 if (s.type()==DocHtmlList::Ordered)
1494 {
1495 m_t << "<ol" << s.attribs().toString();
1496 }
1497 else
1498 {
1499 m_t << "<ul" << s.attribs().toString();
1500 }
1501 m_t << ">\n";
1502 visitChildren(s);
1503 if (s.type()==DocHtmlList::Ordered)
1504 {
1505 m_t << "</ol>";
1506 }
1507 else
1508 {
1509 m_t << "</ul>";
1510 }
1511 if (!s.isPreformatted()) m_t << "\n";
1513}
1514
1516{
1517 if (m_hide) return;
1518 m_t << "<li" << i.attribs().toString() << ">";
1519 if (!i.isPreformatted()) m_t << "\n";
1520 visitChildren(i);
1521 m_t << "</li>\n";
1522}
1523
1525{
1526 if (m_hide) return;
1528 m_t << "<dl" << dl.attribs().toString() << ">\n";
1529 visitChildren(dl);
1530 m_t << "</dl>\n";
1532}
1533
1535{
1536 if (m_hide) return;
1537 m_t << "<dt" << dt.attribs().toString() << ">";
1538 visitChildren(dt);
1539 m_t << "</dt>\n";
1540}
1541
1543{
1544 if (m_hide) return;
1545 m_t << "<dd" << dd.attribs().toString() << ">";
1546 visitChildren(dd);
1547 m_t << "</dd>\n";
1548}
1549
1551{
1552 if (m_hide) return;
1553
1555
1556 if (t.caption())
1557 {
1558 QCString anc = std::get<DocHtmlCaption>(*t.caption()).anchor();
1559 if (!anc.isEmpty())
1560 {
1561 m_t << "<a class=\"anchor\" id=\"" << anc << "\"></a>\n";
1562 }
1563 }
1564
1565 QCString attrs = t.attribs().toString();
1566 if (attrs.isEmpty())
1567 {
1568 m_t << "<table class=\"doxtable\">\n";
1569 }
1570 else
1571 {
1572 m_t << "<table" << t.attribs().toString() << ">\n";
1573 }
1574 if (t.caption())
1575 {
1576 std::visit(*this,*t.caption());
1577 }
1578 visitChildren(t);
1579 m_t << "</table>\n";
1581}
1582
1584{
1585 if (m_hide) return;
1586 m_t << "<tr" << tr.attribs().toString() << ">\n";
1587 visitChildren(tr);
1588 m_t << "</tr>\n";
1589}
1590
1592{
1593 if (m_hide) return;
1594 if (c.isHeading())
1595 {
1596 m_t << "<th" << c.attribs().toString() << ">";
1597 }
1598 else
1599 {
1600 m_t << "<td" << c.attribs().toString() << ">";
1601 }
1602 visitChildren(c);
1603 if (c.isHeading()) m_t << "</th>"; else m_t << "</td>";
1604}
1605
1607{
1608 if (m_hide) return;
1609 m_t << "<caption" << c.attribs().toString() << ">";
1610 visitChildren(c);
1611 m_t << "</caption>\n";
1612}
1613
1615{
1616 if (m_hide) return;
1617 visitChildren(i);
1618}
1619
1621{
1622 if (m_hide) return;
1623 if (href.url().startsWith("mailto:"))
1624 {
1626 }
1627 else
1628 {
1629 QCString url = correctURL(href.url(),href.relPath());
1630 m_t << "<a href=\"" << convertToHtml(url) << "\""
1631 << href.attribs().toString() << ">";
1632 }
1633 visitChildren(href);
1634 m_t << "</a>";
1635}
1636
1638{
1639 if (m_hide) return;
1640 m_t << "<summary " << s.attribs().toString() << ">\n";
1641 visitChildren(s);
1642 m_t << "</summary>\n";
1643}
1644
1646{
1647 if (m_hide) return;
1649 m_t << "<details " << d.attribs().toString() << ">\n";
1650 auto summary = d.summary();
1651 if (summary)
1652 {
1653 std::visit(*this,*summary);
1654 }
1655 visitChildren(d);
1656 m_t << "</details>\n";
1658}
1659
1661{
1662 if (m_hide) return;
1663 forceEndParagraph(header);
1664 m_t << "<h" << header.level() << header.attribs().toString() << ">";
1665 visitChildren(header);
1666 m_t << "</h" << header.level() << ">\n";
1667 forceStartParagraph(header);
1668}
1669
1671{
1672 if (img.type()==DocImage::Html)
1673 {
1674 bool inlineImage = img.isInlineImage();
1675 bool typeSVG = img.isSVG();
1676 QCString url = img.url();
1677
1678 if (!inlineImage)
1679 {
1680 forceEndParagraph(img);
1681 }
1682 if (m_hide) return;
1683 QCString baseName=makeShortName(img.name());
1684 if (!inlineImage) m_t << "<div class=\"image\">\n";
1685 QCString sizeAttribs;
1686 if (!img.width().isEmpty())
1687 {
1688 sizeAttribs+=" width=\""+img.width()+"\"";
1689 }
1690 if (!img.height().isEmpty()) // link to local file
1691 {
1692 sizeAttribs+=" height=\""+img.height()+"\"";
1693 }
1694 // 16 cases: url.isEmpty() | typeSVG | inlineImage | img.hasCaption()
1695
1696 HtmlAttribList attribs = img.attribs();
1697 if (typeSVG)
1698 {
1699 attribs.mergeAttribute("style","pointer-events: none;");
1700 }
1701 QCString alt;
1702 QCString attrs = attribs.toString(&alt);
1703 QCString src;
1704 if (url.isEmpty())
1705 {
1706 src = img.relPath()+img.name();
1707 }
1708 else
1709 {
1710 src = correctURL(url,img.relPath());
1711 }
1712 if (typeSVG && !inlineImage && !src.startsWith("http://") && !src.startsWith("https://"))
1713 {
1714 m_t << "<object type=\"image/svg+xml\" data=\"" << convertToHtml(src)
1715 << "\"" << sizeAttribs << attrs;
1716 if (inlineImage)
1717 {
1718 // skip closing tag
1719 }
1720 else
1721 {
1722 m_t << ">" << alt << "</object>\n";
1723 }
1724 }
1725 else
1726 {
1727 m_t << "<img src=\"" << convertToHtml(src) << "\" alt=\"" << alt << "\"" << sizeAttribs << attrs;
1728 if (inlineImage)
1729 {
1730 m_t << " class=\"inline\"";
1731 }
1732 else
1733 {
1734 m_t << "/>\n";
1735 }
1736 }
1737 if (img.hasCaption())
1738 {
1739 if (inlineImage)
1740 {
1741 m_t << " title=\"";
1742 m_insideTitle=true;
1743 }
1744 else
1745 {
1746 m_t << "<div class=\"caption\">\n";
1747 }
1748 }
1749 else if (inlineImage)
1750 {
1751 m_t << "/>";
1752 }
1753
1754 visitChildren(img);
1755
1756 if (img.hasCaption())
1757 {
1758 if (inlineImage)
1759 {
1760 m_t << "\"/>";
1761 m_insideTitle=false;
1762 }
1763 else // end <div class="caption">
1764 {
1765 m_t << "</div>";
1766 }
1767 }
1768 if (!inlineImage) // end <div class="image">
1769 {
1770 m_t << "</div>\n";
1772 }
1773 }
1774 else // other format -> skip
1775 {
1776 }
1777}
1778
1780{
1781 if (m_hide) return;
1782 if (!Config_getBool(DOT_CLEANUP)) copyFile(df.file(),Config_getString(HTML_OUTPUT)+"/"+stripPath(df.file()));
1784 m_t << "<div class=\"dotgraph\">\n";
1785 writeDotFile(df.file(),df.relPath(),df.context(),df.srcFile(),df.srcLine());
1786 if (df.hasCaption())
1787 {
1788 m_t << "<div class=\"caption\">\n";
1789 }
1790 visitChildren(df);
1791 if (df.hasCaption())
1792 {
1793 m_t << "</div>\n";
1794 }
1795 m_t << "</div>\n";
1797}
1798
1800{
1801 if (m_hide) return;
1802 if (!Config_getBool(DOT_CLEANUP)) copyFile(df.file(),Config_getString(HTML_OUTPUT)+"/"+stripPath(df.file()));
1804 m_t << "<div class=\"mscgraph\">\n";
1805 writeMscFile(df.file(),df.relPath(),df.context(),df.srcFile(),df.srcLine());
1806 if (df.hasCaption())
1807 {
1808 m_t << "<div class=\"caption\">\n";
1809 }
1810 visitChildren(df);
1811 if (df.hasCaption())
1812 {
1813 m_t << "</div>\n";
1814 }
1815 m_t << "</div>\n";
1817}
1818
1820{
1821 if (m_hide) return;
1822 if (!Config_getBool(DOT_CLEANUP)) copyFile(df.file(),Config_getString(HTML_OUTPUT)+"/"+stripPath(df.file()));
1824 m_t << "<div class=\"diagraph\">\n";
1825 writeDiaFile(df.file(),df.relPath(),df.context(),df.srcFile(),df.srcLine());
1826 if (df.hasCaption())
1827 {
1828 m_t << "<div class=\"caption\">\n";
1829 }
1830 visitChildren(df);
1831 if (df.hasCaption())
1832 {
1833 m_t << "</div>\n";
1834 }
1835 m_t << "</div>\n";
1837}
1838
1840{
1841 if (m_hide) return;
1842 if (!Config_getBool(DOT_CLEANUP)) copyFile(df.file(),Config_getString(HTML_OUTPUT)+"/"+stripPath(df.file()));
1844 QCString htmlOutput = Config_getString(HTML_OUTPUT);
1845 QCString imgExt = getDotImageExtension();
1846 PlantumlManager::OutputFormat format = PlantumlManager::PUML_BITMAP; // default : PUML_BITMAP
1847 if (imgExt=="svg")
1848 {
1850 }
1851 std::string inBuf;
1852 readInputFile(df.file(),inBuf);
1854 htmlOutput,QCString(),
1855 inBuf.c_str(),format,QCString(),df.srcFile(),df.srcLine(),false);
1856 baseName=makeBaseName(baseName);
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";
1870}
1871
1873{
1874 if (m_hide) return;
1875 startLink(lnk.ref(),lnk.file(),lnk.relPath(),lnk.anchor());
1876 visitChildren(lnk);
1877 endLink();
1878}
1879
1881{
1882 if (m_hide) return;
1883 if (!ref.file().isEmpty())
1884 {
1885 // when ref.isSubPage()==TRUE we use ref.file() for HTML and
1886 // ref.anchor() for LaTeX/RTF
1887 startLink(ref.ref(),ref.file(),ref.relPath(),ref.isSubPage() ? QCString() : ref.anchor());
1888 }
1889 if (!ref.hasLinkText()) filter(ref.targetTitle());
1890 visitChildren(ref);
1891 if (!ref.file().isEmpty()) endLink();
1892 //m_t << " ";
1893}
1894
1896{
1897 if (m_hide) return;
1898 if (!ref.file().isEmpty())
1899 {
1900 m_t << "<li>";
1901 startLink(ref.ref(),ref.file(),ref.relPath(),ref.isSubPage() ? QCString() : ref.anchor());
1902 }
1903 visitChildren(ref);
1904 if (!ref.file().isEmpty())
1905 {
1906 endLink();
1907 m_t << "</li>\n";
1908 }
1909}
1910
1912{
1913 if (m_hide) return;
1915 m_t << "<div>\n";
1916 m_t << "<ul class=\"multicol\">\n";
1917 visitChildren(s);
1918 m_t << "</ul>\n";
1919 m_t << "</div>\n";
1921}
1922
1924{
1925 if (m_hide) return;
1927 QCString className;
1928 QCString heading;
1929 switch(s.type())
1930 {
1932 heading=theTranslator->trParameters();
1933 className="params";
1934 break;
1936 heading=theTranslator->trReturnValues();
1937 className="retval";
1938 break;
1940 heading=theTranslator->trExceptions();
1941 className="exception";
1942 break;
1944 heading=theTranslator->trTemplateParameters();
1945 className="tparams";
1946 break;
1947 default:
1948 ASSERT(0);
1949 }
1950 m_t << "<dl class=\"" << className << "\"><dt>";
1951 m_t << heading;
1952 m_t << "</dt><dd>\n";
1953 m_t << " <table class=\"" << className << "\">\n";
1954 visitChildren(s);
1955 m_t << " </table>\n";
1956 m_t << " </dd>\n";
1957 m_t << "</dl>\n";
1959}
1960
1962{
1963 if (m_hide) return;
1964 m_t << "&#160;" << s.chars() << "&#160;";
1965}
1966
1968{
1969 //printf("DocParamList::visitPre\n");
1970 if (m_hide) return;
1971 m_t << " <tr>";
1972 const DocParamSect *sect = std::get_if<DocParamSect>(pl.parent());
1973 if (sect && sect->hasInOutSpecifier())
1974 {
1975 m_t << "<td class=\"paramdir\">";
1977 {
1978 m_t << "[";
1979 if (pl.direction()==DocParamSect::In)
1980 {
1981 m_t << "in";
1982 }
1983 else if (pl.direction()==DocParamSect::Out)
1984 {
1985 m_t << "out";
1986 }
1987 else if (pl.direction()==DocParamSect::InOut)
1988 {
1989 m_t << "in,out";
1990 }
1991 m_t << "]";
1992 }
1993 m_t << "</td>";
1994 }
1995 if (sect && sect->hasTypeSpecifier())
1996 {
1997 m_t << "<td class=\"paramtype\">";
1998 for (const auto &type : pl.paramTypes())
1999 {
2000 std::visit(*this,type);
2001 }
2002 m_t << "</td>";
2003 }
2004 m_t << "<td class=\"paramname\">";
2005 bool first=TRUE;
2006 for (const auto &param : pl.parameters())
2007 {
2008 if (!first) m_t << ","; else first=FALSE;
2009 std::visit(*this,param);
2010 }
2011 m_t << "</td><td>";
2012 for (const auto &par : pl.paragraphs())
2013 {
2014 std::visit(*this,par);
2015 }
2016 m_t << "</td></tr>\n";
2017}
2018
2020{
2021 if (m_hide) return;
2022 if (x.title().isEmpty()) return;
2023
2025 bool anonymousEnum = x.file()=="@";
2026 if (!anonymousEnum)
2027 {
2028 QCString fn = x.file();
2030 m_t << "<dl class=\"" << x.key() << "\"><dt><b><a class=\"el\" href=\""
2031 << x.relPath() << fn
2032 << "#" << x.anchor() << "\">";
2033 }
2034 else
2035 {
2036 m_t << "<dl class=\"" << x.key() << "\"><dt><b>";
2037 }
2038 filter(x.title());
2039 if (!anonymousEnum) m_t << "</a>";
2040 m_t << "</b></dt><dd>";
2041 visitChildren(x);
2042 if (x.title().isEmpty()) return;
2043 m_t << "</dd></dl>\n";
2045}
2046
2048{
2049 if (m_hide) return;
2050 startLink(QCString(),ref.file(),ref.relPath(),ref.anchor());
2051 visitChildren(ref);
2052 endLink();
2053 m_t << " ";
2054}
2055
2057{
2058 visitChildren(t);
2059}
2060
2062{
2063 if (m_hide) return;
2065 m_t << "<blockquote class=\"doxtable\"" << b.attribs().toString() << ">\n";
2066 visitChildren(b);
2067 m_t << "</blockquote>\n";
2069}
2070
2072{
2073 if (m_hide) return;
2074 if (VhdlDocGen::getFlowMember()) // use VHDL flow chart creator
2075 {
2078 m_t << "<p>";
2079 m_t << theTranslator->trFlowchart();
2080 m_t << " ";
2081 m_t << "<a href=\"";
2082 m_t << fname;
2083 m_t << ".svg\">";
2085 m_t << "</a>";
2086 if (vf.hasCaption())
2087 {
2088 m_t << "<br />";
2089 }
2090 }
2091 visitChildren(vf);
2092 if (VhdlDocGen::getFlowMember()) // use VHDL flow chart creator
2093 {
2094 m_t << "</p>";
2096 }
2097}
2098
2100{
2101 if (m_hide) return;
2102 visitChildren(pb);
2103}
2104
2105void HtmlDocVisitor::filter(const QCString &str, const bool retainNewline)
2106{
2107 if (str.isEmpty()) return;
2108 const char *p=str.data();
2109 while (*p)
2110 {
2111 char c=*p++;
2112 switch(c)
2113 {
2114 case '\n': if(retainNewline) m_t << "<br/>"; m_t << c; break;
2115 case '<': m_t << "&lt;"; break;
2116 case '>': m_t << "&gt;"; break;
2117 case '&': m_t << "&amp;"; break;
2118 case '\\': if ((*p == '(') || (*p == ')'))
2119 m_t << "\\&zwj;" << *p++;
2120 else
2121 m_t << c;
2122 break;
2123 default:
2124 {
2125 uint8_t uc = static_cast<uint8_t>(c);
2126 if (uc<32 && !isspace(c)) // non-printable control characters
2127 {
2128 m_t << "&#x24" << hex[uc>>4] << hex[uc&0xF] << ";";
2129 }
2130 else
2131 {
2132 m_t << c;
2133 }
2134 }
2135 break;
2136 }
2137 }
2138}
2139
2140/// Escape basic entities to produce a valid CDATA attribute value,
2141/// assume that the outer quoting will be using the double quote &quot;
2143{
2144 GrowBuf growBuf;
2145 if (str.isEmpty()) return str;
2146 const char *p=str.data();
2147 while (*p)
2148 {
2149 char c=*p++;
2150 switch(c)
2151 {
2152 case '&': growBuf.addStr("&amp;"); break;
2153 case '"': growBuf.addStr("&quot;"); break;
2154 case '<': growBuf.addStr("&lt;"); break;
2155 case '>': growBuf.addStr("&gt;"); break;
2156 case '\\':
2157 if ((*p == '(') || (*p == ')'))
2158 {
2159 growBuf.addStr("\\&zwj;");
2160 growBuf.addChar(*p++);
2161 }
2162 else
2163 {
2164 growBuf.addChar(c);
2165 }
2166 break;
2167 default:
2168 {
2169 uint8_t uc = static_cast<uint8_t>(c);
2170 if (uc<32 && !isspace(c)) // non-printable control characters
2171 {
2172 growBuf.addStr("&#x24");
2173 growBuf.addChar(hex[uc>>4]);
2174 growBuf.addChar(hex[uc&0xF]);
2175 growBuf.addStr(";");
2176 }
2177 else
2178 {
2179 growBuf.addChar(c);
2180 }
2181 }
2182 break;
2183 }
2184 }
2185 growBuf.addChar(0);
2186 return growBuf.get();
2187}
2188
2189void HtmlDocVisitor::startLink(const QCString &ref,const QCString &file,
2190 const QCString &relPath,const QCString &anchor,
2191 const QCString &tooltip)
2192{
2193 //printf("HtmlDocVisitor: file=%s anchor=%s\n",qPrint(file),qPrint(anchor));
2194 if (!ref.isEmpty()) // link to entity imported via tag file
2195 {
2196 m_t << "<a class=\"elRef\" ";
2198 }
2199 else // local link
2200 {
2201 m_t << "<a class=\"el\" ";
2202 }
2203 m_t << "href=\"";
2204 QCString fn = file;
2206 m_t << createHtmlUrl(relPath,ref,true,
2207 m_fileName == Config_getString(HTML_OUTPUT)+"/"+fn,
2208 fn,
2209 anchor);
2210 m_t << "\"";
2211 if (!tooltip.isEmpty()) m_t << " title=\"" << convertToHtml(tooltip) << "\"";
2212 m_t << ">";
2213}
2214
2216{
2217 m_t << "</a>";
2218}
2219
2220void HtmlDocVisitor::writeDotFile(const QCString &fn,const QCString &relPath,
2221 const QCString &context,const QCString &srcFile,int srcLine)
2222{
2223 QCString baseName=makeBaseName(fn);
2224 baseName.prepend("dot_");
2225 QCString outDir = Config_getString(HTML_OUTPUT);
2226 writeDotGraphFromFile(fn,outDir,baseName,GraphOutputFormat::BITMAP,srcFile,srcLine);
2227 writeDotImageMapFromFile(m_t,fn,outDir,relPath,baseName,context,-1,srcFile,srcLine);
2228}
2229
2230void HtmlDocVisitor::writeMscFile(const QCString &fileName,const QCString &relPath,
2231 const QCString &context,const QCString &srcFile,int srcLine)
2232{
2233 QCString baseName=makeBaseName(fileName);
2234 baseName.prepend("msc_");
2235 QCString outDir = Config_getString(HTML_OUTPUT);
2236 QCString imgExt = getDotImageExtension();
2238 if ("svg" == imgExt)
2239 mscFormat = MscOutputFormat::SVG;
2240 writeMscGraphFromFile(fileName,outDir,baseName,mscFormat,srcFile,srcLine);
2241 writeMscImageMapFromFile(m_t,fileName,outDir,relPath,baseName,context,mscFormat,srcFile,srcLine);
2242}
2243
2244void HtmlDocVisitor::writeDiaFile(const QCString &fileName, const QCString &relPath,
2245 const QCString &,const QCString &srcFile,int srcLine)
2246{
2247 QCString baseName=makeBaseName(fileName);
2248 baseName.prepend("dia_");
2249 QCString outDir = Config_getString(HTML_OUTPUT);
2250 writeDiaGraphFromFile(fileName,outDir,baseName,DiaOutputFormat::BITMAP,srcFile,srcLine);
2251
2252 m_t << "<img src=\"" << relPath << baseName << ".png" << "\" />\n";
2253}
2254
2255void HtmlDocVisitor::writePlantUMLFile(const QCString &fileName, const QCString &relPath,
2256 const QCString &,const QCString &/* srcFile */,int /* srcLine */)
2257{
2258 QCString baseName=makeBaseName(fileName);
2259 QCString outDir = Config_getString(HTML_OUTPUT);
2260 QCString imgExt = getDotImageExtension();
2261 if (imgExt=="svg")
2262 {
2264 //m_t << "<iframe scrolling=\"no\" frameborder=\"0\" src=\"" << relPath << baseName << ".svg" << "\" />\n";
2265 //m_t << "<p><b>This browser is not able to show SVG: try Firefox, Chrome, Safari, or Opera instead.</b></p>";
2266 //m_t << "</iframe>\n";
2267 m_t << "<object type=\"image/svg+xml\" data=\"" << relPath << baseName << ".svg\"></object>\n";
2268 }
2269 else
2270 {
2272 m_t << "<img src=\"" << relPath << baseName << ".png" << "\" />\n";
2273 }
2274}
2275
2276/** Returns TRUE if the child nodes in paragraph \a para until \a nodeIndex
2277 contain a style change node that is still active and that style change is one that
2278 must be located outside of a paragraph, i.e. it is a center, div, or pre tag.
2279 See also bug746162.
2280 */
2283{
2284 //printf("insideStyleChangeThatIsOutputParagraph(index=%d)\n",nodeIndex);
2285 int styleMask=0;
2286 bool styleOutsideParagraph=FALSE;
2287 while (!styleOutsideParagraph)
2288 {
2289 const DocNodeVariant *n = &(*it);
2290 const DocStyleChange *sc = std::get_if<DocStyleChange>(n);
2291 if (sc)
2292 {
2293 if (!sc->enable()) // remember styles that has been closed already
2294 {
2295 styleMask|=static_cast<int>(sc->style());
2296 }
2297 bool paraStyle = sc->style()==DocStyleChange::Center ||
2298 sc->style()==DocStyleChange::Div ||
2300 //printf("Found style change %s enabled=%d\n",sc->styleString(),sc->enable());
2301 if (sc->enable() && (styleMask&static_cast<int>(sc->style()))==0 && // style change that is still active
2302 paraStyle
2303 )
2304 {
2305 styleOutsideParagraph=TRUE;
2306 }
2307 }
2308 if (it!=std::begin(para->children()))
2309 {
2310 --it;
2311 }
2312 else
2313 {
2314 break;
2315 }
2316 }
2317 return styleOutsideParagraph;
2318}
2319
2320/** Used for items found inside a paragraph, which due to XHTML restrictions
2321 * have to be outside of the paragraph. This method will forcefully end
2322 * the current paragraph and forceStartParagraph() will restart it.
2323 */
2324template<class Node>
2326{
2327 const DocPara *para=std::get_if<DocPara>(n.parent());
2328 if (para)
2329 {
2330 const DocNodeList &children = para->children();
2331
2332 //printf("forceEndParagraph\n");
2333 //dumpDocNodeList(children);
2334
2335 auto it = std::find_if(std::begin(children),std::end(children),
2336 [&n](const auto &np) { return holds_value(&n,np); });
2337 if (it==std::end(children)) return;
2338 if (it==std::begin(children)) return; // first node in paragraph
2339 it = std::prev(it);
2340 bool found=false;
2341 while (!found)
2342 {
2343 found = !isInvisibleNode(*it);
2344 if (found) break;
2345 if (it!=std::begin(children))
2346 {
2347 --it;
2348 }
2349 else
2350 {
2351 break;
2352 }
2353 }
2354 if (!found) return; // first visible node in paragraph
2355 const DocNodeVariant &v = *it;
2356 if (mustBeOutsideParagraph(v)) return; // previous node already outside paragraph context
2357 bool styleOutsideParagraph=false;
2358 if (it!=std::begin(children))
2359 {
2360 it = std::prev(it);
2361 styleOutsideParagraph=insideStyleChangeThatIsOutsideParagraph(para,it);
2362 }
2363 bool isFirst = false;
2364 bool isLast = false;
2365 getParagraphContext(*para,isFirst,isLast);
2366 //printf("forceEnd first=%d last=%d styleOutsideParagraph=%d\n",isFirst,isLast,styleOutsideParagraph);
2367 if (isFirst && isLast) return;
2368 if (styleOutsideParagraph) return;
2369
2370 //printf("adding </p>\n");
2371 m_t << "</p>";
2372 }
2373}
2374
2375/** Used for items found inside a paragraph, which due to XHTML restrictions
2376 * have to be outside of the paragraph. This method will forcefully start
2377 * the paragraph, that was previously ended by forceEndParagraph().
2378 */
2379template<class Node>
2381{
2382 //printf("> forceStartParagraph(%s)\n",docNodeName(n));
2383 const DocPara *para=nullptr;
2384 if (n.parent() && (para = std::get_if<DocPara>(n.parent()))) // if we are inside a paragraph
2385 {
2386 const DocNodeList &children = para->children();
2387
2388 auto it = std::find_if(std::begin(children),
2389 std::end(children),
2390 [&n](const auto &np)
2391 { return holds_value(&n,np); });
2392 if (it==std::end(children)) return;
2393 bool styleOutsideParagraph=insideStyleChangeThatIsOutsideParagraph(para,it);
2394 //printf("it=%s (%p) styleOutsideParagraph=%d\n",
2395 // docNodeName(*it), (void *)&*it, styleOutsideParagraph);
2396 if (styleOutsideParagraph) return;
2397 it = std::next(it);
2398 while (it!=std::end(children) && isInvisibleNode(*it))
2399 {
2400 ++it;
2401 }
2402 if (it!=std::end(children))
2403 {
2404 const DocNodeVariant &v = *it;
2405 if (mustBeOutsideParagraph(v)) return; // next element also outside paragraph
2406 }
2407 else
2408 {
2409 return; // only whitespace at the end!
2410 }
2411
2412 bool needsTag = true;
2413 bool isFirst = false;
2414 bool isLast = false;
2415 getParagraphContext(*para,isFirst,isLast);
2416 if (isFirst && isLast) needsTag = false;
2417 //printf("forceStart first=%d last=%d needsTag=%d\n",isFirst,isLast,needsTag);
2418
2419 if (needsTag) m_t << "<p>";
2420 }
2421}
2422
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, bool isExampleBlock, const QCString &exampleName=QCString(), const FileDef *fileDef=nullptr, int startLine=-1, int endLine=-1, bool inlineFragment=FALSE, const MemberDef *memberDef=nullptr, bool showLineNumbers=TRUE, const Definition *searchCtx=nullptr, bool collectXRefs=TRUE)=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:76
virtual QCString anchor() const =0
virtual QCString getDefFileExtension() const =0
virtual const QCString & name() const =0
Class representing a directory in the file system.
Definition dir.h:75
bool remove(const std::string &path, bool acceptsAbsPath=true) const
Definition dir.cpp:314
Node representing an anchor.
Definition docnode.h:228
const HtmlAttribList & attribs() const
Definition docnode.h:234
QCString anchor() const
Definition docnode.h:231
Node representing an auto List.
Definition docnode.h:567
bool isCheckedList() const
Definition docnode.h:578
bool isEnumList() const
Definition docnode.h:576
int depth() const
Definition docnode.h:579
Node representing an item of a auto list.
Definition docnode.h:591
int itemNumber() const
Definition docnode.h:594
Node representing a citation of some bibliographic reference.
Definition docnode.h:244
QCString text() const
Definition docnode.h:251
QCString relPath() const
Definition docnode.h:248
QCString anchor() const
Definition docnode.h:250
QCString ref() const
Definition docnode.h:249
QCString file() const
Definition docnode.h:247
DocNodeList & children()
Definition docnode.h:142
Node representing a dia file.
Definition docnode.h:726
QCString relPath() const
Definition docnode.h:681
QCString srcFile() const
Definition docnode.h:686
QCString file() const
Definition docnode.h:680
int srcLine() const
Definition docnode.h:687
bool hasCaption() const
Definition docnode.h:682
QCString context() const
Definition docnode.h:685
Node representing a dot file.
Definition docnode.h:708
Node representing an emoji.
Definition docnode.h:337
int index() const
Definition docnode.h:341
QCString name() const
Definition docnode.h:340
Node representing an item of a cross-referenced list.
Definition docnode.h:525
QCString text() const
Definition docnode.h:529
QCString name() const
Definition docnode.h:528
bool isInline() const
Definition docnode.h:532
int id() const
Definition docnode.h:531
QCString relPath() const
Definition docnode.h:530
Node representing a Hypertext reference.
Definition docnode.h:818
QCString url() const
Definition docnode.h:825
QCString relPath() const
Definition docnode.h:827
const HtmlAttribList & attribs() const
Definition docnode.h:828
Node representing a horizontal ruler.
Definition docnode.h:215
const HtmlAttribList & attribs() const
Definition docnode.h:220
Node representing an HTML blockquote.
Definition docnode.h:1286
const HtmlAttribList & attribs() const
Definition docnode.h:1291
Node representing a HTML table caption.
Definition docnode.h:1223
const HtmlAttribList & attribs() const
Definition docnode.h:1226
Node representing a HTML table cell.
Definition docnode.h:1188
bool isHeading() const
Definition docnode.h:1195
const HtmlAttribList & attribs() const
Definition docnode.h:1200
Node representing a HTML description data.
Definition docnode.h:1176
const HtmlAttribList & attribs() const
Definition docnode.h:1179
Node representing a Html description list.
Definition docnode.h:896
const HtmlAttribList & attribs() const
Definition docnode.h:900
Node representing a Html description item.
Definition docnode.h:883
const HtmlAttribList & attribs() const
Definition docnode.h:887
Node Html details.
Definition docnode.h:852
const HtmlAttribList & attribs() const
Definition docnode.h:856
const DocNodeVariant * summary() const
Definition docnode.h:859
Node Html heading.
Definition docnode.h:868
const HtmlAttribList & attribs() const
Definition docnode.h:873
int level() const
Definition docnode.h:872
Node representing a Html list.
Definition docnode.h:995
const HtmlAttribList & attribs() const
Definition docnode.h:1001
Type type() const
Definition docnode.h:1000
Node representing a HTML list item.
Definition docnode.h:1160
const HtmlAttribList & attribs() const
Definition docnode.h:1165
Node representing a HTML table row.
Definition docnode.h:1241
const HtmlAttribList & attribs() const
Definition docnode.h:1247
Node Html summary.
Definition docnode.h:839
const HtmlAttribList & attribs() const
Definition docnode.h:843
Node representing a HTML table.
Definition docnode.h:1264
const DocNodeVariant * caption() const
Definition docnode.cpp:2047
const HtmlAttribList & attribs() const
Definition docnode.h:1270
Node representing an image.
Definition docnode.h:637
const HtmlAttribList & attribs() const
Definition docnode.h:651
QCString relPath() const
Definition docnode.h:647
QCString name() const
Definition docnode.h:643
QCString url() const
Definition docnode.h:648
QCString height() const
Definition docnode.h:646
Type type() const
Definition docnode.h:642
QCString width() const
Definition docnode.h:645
bool isInlineImage() const
Definition docnode.h:649
bool isSVG() const
Definition docnode.cpp:1266
bool hasCaption() const
Definition docnode.h:644
Node representing a include/dontinclude operator block.
Definition docnode.h:473
bool stripCodeComments() const
Definition docnode.h:502
bool isLast() const
Definition docnode.h:499
QCString includeFileName() const
Definition docnode.h:505
QCString text() const
Definition docnode.h:495
QCString context() const
Definition docnode.h:497
QCString exampleFile() const
Definition docnode.h:504
int line() const
Definition docnode.h:493
Type type() const
Definition docnode.h:481
bool isFirst() const
Definition docnode.h:498
bool showLineNo() const
Definition docnode.h:494
bool isExample() const
Definition docnode.h:503
Node representing an included text block from file.
Definition docnode.h:431
QCString blockId() const
Definition docnode.h:450
QCString extension() const
Definition docnode.h:446
bool isBlock() const
Definition docnode.h:454
bool stripCodeComments() const
Definition docnode.h:451
@ LatexInclude
Definition docnode.h:433
@ SnippetWithLines
Definition docnode.h:434
@ DontIncWithLines
Definition docnode.h:435
@ IncWithLines
Definition docnode.h:434
@ HtmlInclude
Definition docnode.h:433
@ VerbInclude
Definition docnode.h:433
@ DontInclude
Definition docnode.h:433
@ DocbookInclude
Definition docnode.h:435
Type type() const
Definition docnode.h:447
QCString exampleFile() const
Definition docnode.h:453
QCString text() const
Definition docnode.h:448
QCString file() const
Definition docnode.h:445
bool trimLeft() const
Definition docnode.h:455
bool isExample() const
Definition docnode.h:452
QCString context() const
Definition docnode.h:449
Node representing an entry in the index.
Definition docnode.h:548
QCString entry() const
Definition docnode.h:555
const Definition * scope() const
Definition docnode.h:553
const MemberDef * member() const
Definition docnode.h:554
Node representing an internal section of documentation.
Definition docnode.h:964
Node representing an internal reference to some item.
Definition docnode.h:802
QCString file() const
Definition docnode.h:806
QCString relPath() const
Definition docnode.h:807
QCString anchor() const
Definition docnode.h:808
Node representing a line break.
Definition docnode.h:201
const HtmlAttribList & attribs() const
Definition docnode.h:207
Node representing a word that can be linked to something.
Definition docnode.h:164
QCString file() const
Definition docnode.h:170
QCString relPath() const
Definition docnode.h:171
QCString ref() const
Definition docnode.h:172
QCString word() const
Definition docnode.h:169
QCString anchor() const
Definition docnode.h:173
QCString tooltip() const
Definition docnode.h:174
Node representing a msc file.
Definition docnode.h:717
Abstract node interface with type information.
Definition docnode.h:81
bool isPreformatted() const
Definition docnode.h:104
DocNodeVariant * parent()
Definition docnode.h:89
Node representing an block of paragraphs.
Definition docnode.h:974
Node representing a paragraph in the documentation tree.
Definition docnode.h:1075
const HtmlAttribList & attribs() const
Definition docnode.h:1109
Node representing a parameter list.
Definition docnode.h:1120
const DocNodeList & parameters() const
Definition docnode.h:1124
const DocNodeList & paramTypes() const
Definition docnode.h:1125
DocParamSect::Direction direction() const
Definition docnode.h:1128
const DocNodeList & paragraphs() const
Definition docnode.h:1126
Node representing a parameter section.
Definition docnode.h:1048
bool hasInOutSpecifier() const
Definition docnode.h:1064
bool hasTypeSpecifier() const
Definition docnode.h:1065
Type type() const
Definition docnode.h:1063
Node representing a uml file.
Definition docnode.h:735
Node representing a reference to some item.
Definition docnode.h:773
QCString anchor() const
Definition docnode.h:780
QCString relPath() const
Definition docnode.h:778
QCString targetTitle() const
Definition docnode.h:781
bool isSubPage() const
Definition docnode.h:787
QCString file() const
Definition docnode.h:777
QCString ref() const
Definition docnode.h:779
bool hasLinkText() const
Definition docnode.h:783
Root node of documentation tree.
Definition docnode.h:1308
Node representing a reference to a section.
Definition docnode.h:930
QCString relPath() const
Definition docnode.h:936
QCString file() const
Definition docnode.h:934
QCString anchor() const
Definition docnode.h:935
QCString ref() const
Definition docnode.h:937
bool isSubPage() const
Definition docnode.h:939
Node representing a list of section references.
Definition docnode.h:954
Node representing a normal section.
Definition docnode.h:909
int level() const
Definition docnode.h:913
QCString anchor() const
Definition docnode.h:915
const DocNodeVariant * title() const
Definition docnode.h:914
Node representing a separator.
Definition docnode.h:361
QCString chars() const
Definition docnode.h:365
Node representing a simple list.
Definition docnode.h:985
Node representing a simple list item.
Definition docnode.h:1148
const DocNodeVariant * paragraph() const
Definition docnode.h:1152
Node representing a simple section.
Definition docnode.h:1012
QCString typeString() const
Definition docnode.cpp:3026
Type type() const
Definition docnode.h:1021
const DocNodeVariant * title() const
Definition docnode.h:1028
Node representing a separator between two simple sections of the same type.
Definition docnode.h:1039
Node representing a style change.
Definition docnode.h:264
const HtmlAttribList & attribs() const
Definition docnode.h:307
QCString tagName() const
Definition docnode.h:308
Style style() const
Definition docnode.h:303
bool enable() const
Definition docnode.h:305
Node representing a special symbol.
Definition docnode.h:324
HtmlEntityMapper::SymType symbol() const
Definition docnode.h:328
Root node of a text fragment.
Definition docnode.h:1299
Node representing a simple section title.
Definition docnode.h:604
Node representing a URL (or email address)
Definition docnode.h:187
QCString url() const
Definition docnode.h:191
bool isEmail() const
Definition docnode.h:192
Node representing a verbatim, unparsed text fragment.
Definition docnode.h:372
QCString srcFile() const
Definition docnode.h:393
int srcLine() const
Definition docnode.h:394
QCString language() const
Definition docnode.h:384
bool isBlock() const
Definition docnode.h:385
bool isExample() const
Definition docnode.h:381
QCString context() const
Definition docnode.h:380
Type type() const
Definition docnode.h:378
QCString text() const
Definition docnode.h:379
QCString exampleFile() const
Definition docnode.h:382
QCString engine() const
Definition docnode.h:389
QCString relPath() const
Definition docnode.h:383
@ JavaDocLiteral
Definition docnode.h:374
Node representing a VHDL flow chart.
Definition docnode.h:744
bool hasCaption() const
Definition docnode.h:748
CodeParserInterface & getCodeParser(const QCString &langExt)
void pushHidden(bool hide)
bool popHidden()
Node representing some amount of white space.
Definition docnode.h:350
QCString chars() const
Definition docnode.h:354
Node representing a word.
Definition docnode.h:152
QCString word() const
Definition docnode.h:155
Node representing an item of a cross-referenced list.
Definition docnode.h:616
QCString anchor() const
Definition docnode.h:620
QCString key() const
Definition docnode.h:623
QCString relPath() const
Definition docnode.h:622
QCString file() const
Definition docnode.h:619
QCString title() const
Definition docnode.h:621
static IndexList * indexList
Definition doxygen.h:134
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:54
Class representing a string buffer optimized for growing.
Definition growbuf.h:28
void addChar(char c)
Definition growbuf.h:69
void addStr(const QCString &s)
Definition growbuf.h:72
char * get()
Definition growbuf.h:114
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 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 writeDotFile(const QCString &fileName, const QCString &relPath, const QCString &context, const QCString &srcFile, int srcLine)
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 writeDiaFile(const QCString &fileName, const QCString &relPath, const QCString &context, const QCString &srcFile, int srcLine)
void writeMscFile(const QCString &fileName, const QCString &relPath, const QCString &context, const QCString &srcFile, int srcLine)
void visitChildren(const T &t)
void filter(const QCString &str, const bool retainNewline=false)
void forceEndParagraph(const DocNode &n)
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.
Class representing a list of different code generators.
Definition outputlist.h:164
QCString 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:28
OutputFormat
Plant UML output image formats.
Definition plantuml.h:44
static PlantumlManager & instance()
Definition plantuml.cpp:157
void generatePlantUMLOutput(const QCString &baseName, const QCString &outDir, OutputFormat format)
Convert a PlantUML file to an image.
Definition plantuml.cpp:128
This is an alternative implementation of QCString.
Definition qcstring.h:101
int find(char c, int index=0, bool cs=TRUE) const
Definition qcstring.cpp:43
QCString & prepend(const char *s)
Definition qcstring.h:407
size_t length() const
Returns the length of the string, not counting the 0-terminator.
Definition qcstring.h:153
bool startsWith(const char *s) const
Definition qcstring.h:492
QCString mid(size_t index, size_t len=static_cast< size_t >(-1)) const
Definition qcstring.h:226
char & at(size_t i)
Returns a reference to the character at index i.
Definition qcstring.h:578
bool isEmpty() const
Returns TRUE iff the string is empty.
Definition qcstring.h:150
const std::string & str() const
Definition qcstring.h:537
QCString & setNum(short n)
Definition qcstring.h:444
QCString & sprintf(const char *format,...)
Definition qcstring.cpp:29
@ ExplicitSize
Definition qcstring.h:133
int findRev(char c, int index=-1, bool cs=TRUE) const
Definition qcstring.cpp:91
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:159
QCString left(size_t len) const
Definition qcstring.h:214
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:229
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)
Definition dia.cpp:26
static constexpr auto hex
static QCString makeBaseName(const QCString &name)
static QCString makeShortName(const QCString &baseName)
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 > DocNodeVariant
Definition docnode.h:66
constexpr bool holds_one_of_alternatives(const DocNodeVariant &v)
returns true iff v holds one of types passed as template parameters
Definition docnode.h:1361
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:1325
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)
Definition dot.cpp:283
void writeDotGraphFromFile(const QCString &inFile, const QCString &outDir, const QCString &outFile, GraphOutputFormat format, const QCString &srcFile, int srcLine)
Definition dot.cpp:230
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 QCString makeBaseName(const QCString &name)
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 QCString makeShortName(const QCString &name)
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)
Definition msc.cpp:157
MscOutputFormat
Definition msc.h:22
std::ofstream openOutputStream(const QCString &name, bool append=false)
Definition portable.cpp:665
Portable versions of functions that are platform dependent.
const char * qPrint(const char *s)
Definition qcstring.h:672
#define TRUE
Definition qcstring.h:37
#define FALSE
Definition qcstring.h:34
#define ASSERT(x)
Definition qcstring.h:39
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
SrcLangExt getLanguageFromFileName(const QCString &fileName, SrcLangExt defLang)
Definition util.cpp:5722
QCString convertToHtml(const QCString &s, bool keepEntities)
Definition util.cpp:4480
QCString correctURL(const QCString &url, const QCString &relPath)
Corrects URL url according to the relative path relPath.
Definition util.cpp:6443
QCString stripPath(const QCString &s)
Definition util.cpp:5465
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:6052
SrcLangExt getLanguageFromCodeLang(QCString &fileName)
Routine to handle the language attribute of the \code command.
Definition util.cpp:5740
QCString getDotImageExtension()
Definition util.cpp:6805
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:6375
QCString externalLinkTarget(const bool parent)
Definition util.cpp:6227
QCString getFileNameExtension(const QCString &fn)
Definition util.cpp:5764
void addHtmlExtensionIfMissing(QCString &fName)
Definition util.cpp:5416
QCString createHtmlUrl(const QCString &relPath, const QCString &ref, bool href, bool isLocalFile, const QCString &targetFileName, const QCString &anchor)
Definition util.cpp:6238
A bunch of utility functions.