From 83f2af252d2b24856cfeabb612dc932fd8be4ff5 Mon Sep 17 00:00:00 2001
From: Thibaut Cuvelier <cuvelier.thibaut@gmail.com>
Date: Fri, 10 May 2019 01:35:59 +0200
Subject: [PATCH 05/18] Add sections to HTML output.

Only for HTML5.
---
 src/output_xhtml.cpp | 156 +++++++++++++++++++++++++------------------
 1 file changed, 92 insertions(+), 64 deletions(-)

diff --git a/src/output_xhtml.cpp b/src/output_xhtml.cpp
index be2a71e3dc..39929b6ffa 100644
--- a/src/output_xhtml.cpp
+++ b/src/output_xhtml.cpp
@@ -34,7 +34,7 @@
 #include "support/lstrings.h"
 #include "support/textutils.h"
 
-#include <vector>
+#include <stack>
 
 // Uncomment to activate debugging code.
 // #define XHTML_DEBUG
@@ -47,44 +47,44 @@ namespace lyx {
 
 docstring const & fontToHtmlTag(xml::FontTypes type)
 {
-    switch(type) {
-        case xml::FontTypes::FT_EMPH:
-            return from_utf8("em");
-        case xml::FontTypes::FT_BOLD:
-            return from_utf8("b");
-        case xml::FontTypes::FT_NOUN:
-            return from_utf8("dfn");
-        case xml::FontTypes::FT_UBAR:
-        case xml::FontTypes::FT_WAVE:
-        case xml::FontTypes::FT_DBAR:
-            return from_utf8("u");
-        case xml::FontTypes::FT_SOUT:
-        case xml::FontTypes::FT_XOUT:
-            return from_utf8("del");
-        case xml::FontTypes::FT_ITALIC:
-            return from_utf8("i");
-        case xml::FontTypes::FT_UPRIGHT:
-        case xml::FontTypes::FT_SLANTED:
-        case xml::FontTypes::FT_SMALLCAPS:
-        case xml::FontTypes::FT_ROMAN:
-        case xml::FontTypes::FT_SANS:
-        case xml::FontTypes::FT_TYPE:
-        case xml::FontTypes::FT_SIZE_TINY:
-        case xml::FontTypes::FT_SIZE_SCRIPT:
-        case xml::FontTypes::FT_SIZE_FOOTNOTE:
-        case xml::FontTypes::FT_SIZE_SMALL:
-        case xml::FontTypes::FT_SIZE_NORMAL:
-        case xml::FontTypes::FT_SIZE_LARGE:
-        case xml::FontTypes::FT_SIZE_LARGER:
-        case xml::FontTypes::FT_SIZE_LARGEST:
-        case xml::FontTypes::FT_SIZE_HUGE:
-        case xml::FontTypes::FT_SIZE_HUGER:
-        case xml::FontTypes::FT_SIZE_INCREASE:
-        case xml::FontTypes::FT_SIZE_DECREASE:
-            return from_utf8("span");
-    }
-    // kill warning
-    return docstring();
+	switch(type) {
+	case xml::FontTypes::FT_EMPH:
+		return from_utf8("em");
+	case xml::FontTypes::FT_BOLD:
+		return from_utf8("b");
+	case xml::FontTypes::FT_NOUN:
+		return from_utf8("dfn");
+	case xml::FontTypes::FT_UBAR:
+	case xml::FontTypes::FT_WAVE:
+	case xml::FontTypes::FT_DBAR:
+		return from_utf8("u");
+	case xml::FontTypes::FT_SOUT:
+	case xml::FontTypes::FT_XOUT:
+		return from_utf8("del");
+	case xml::FontTypes::FT_ITALIC:
+		return from_utf8("i");
+	case xml::FontTypes::FT_UPRIGHT:
+	case xml::FontTypes::FT_SLANTED:
+	case xml::FontTypes::FT_SMALLCAPS:
+	case xml::FontTypes::FT_ROMAN:
+	case xml::FontTypes::FT_SANS:
+	case xml::FontTypes::FT_TYPE:
+	case xml::FontTypes::FT_SIZE_TINY:
+	case xml::FontTypes::FT_SIZE_SCRIPT:
+	case xml::FontTypes::FT_SIZE_FOOTNOTE:
+	case xml::FontTypes::FT_SIZE_SMALL:
+	case xml::FontTypes::FT_SIZE_NORMAL:
+	case xml::FontTypes::FT_SIZE_LARGE:
+	case xml::FontTypes::FT_SIZE_LARGER:
+	case xml::FontTypes::FT_SIZE_LARGEST:
+	case xml::FontTypes::FT_SIZE_HUGE:
+	case xml::FontTypes::FT_SIZE_HUGER:
+	case xml::FontTypes::FT_SIZE_INCREASE:
+	case xml::FontTypes::FT_SIZE_DECREASE:
+		return from_utf8("span");
+	}
+	// kill warning
+	return docstring();
 }
 
 
@@ -165,15 +165,15 @@ namespace {
 // convenience functions
 
 inline void openParTag(XMLStream & xs, Layout const & lay,
-                       std::string parlabel)
+					   std::string parlabel)
 {
 	xs << xml::ParTag(lay.htmltag(), lay.htmlattr(), parlabel);
 }
 
 
 void openParTag(XMLStream & xs, Layout const & lay,
-                ParagraphParameters const & params,
-                std::string parlabel)
+				ParagraphParameters const & params,
+				std::string parlabel)
 {
 	// FIXME Are there other things we should handle here?
 	string const align = alignmentToCSS(params.align());
@@ -211,7 +211,7 @@ inline void openItemTag(XMLStream & xs, Layout const & lay)
 
 
 void openItemTag(XMLStream & xs, Layout const & lay,
-             ParagraphParameters const & params)
+			 ParagraphParameters const & params)
 {
 	// FIXME Are there other things we should handle here?
 	string const align = alignmentToCSS(params.align());
@@ -276,11 +276,11 @@ ParagraphList::const_iterator findEndOfEnvironment(
 
 
 ParagraphList::const_iterator makeParagraphs(Buffer const & buf,
-					    XMLStream & xs,
-					    OutputParams const & runparams,
-					    Text const & text,
-					    ParagraphList::const_iterator const & pbegin,
-					    ParagraphList::const_iterator const & pend)
+						XMLStream & xs,
+						OutputParams const & runparams,
+						Text const & text,
+						ParagraphList::const_iterator const & pbegin,
+						ParagraphList::const_iterator const & pend)
 {
 	ParagraphList::const_iterator const begin = text.paragraphs().begin();
 	ParagraphList::const_iterator par = pbegin;
@@ -288,7 +288,7 @@ ParagraphList::const_iterator makeParagraphs(Buffer const & buf,
 		Layout const & lay = par->layout();
 		if (!lay.counter.empty())
 			buf.masterBuffer()->params().
-			    documentClass().counters().step(lay.counter, OutputUpdate);
+				documentClass().counters().step(lay.counter, OutputUpdate);
 
 		// FIXME We should see if there's a label to be output and
 		// do something with it.
@@ -317,7 +317,7 @@ ParagraphList::const_iterator makeParagraphs(Buffer const & buf,
 						style.labelfont : style.font;
 			FontInfo const our_font =
 				par->getFont(buf.masterBuffer()->params(), 0,
-			               text.outerFont(distance(begin, par))).fontInfo();
+						   text.outerFont(distance(begin, par))).fontInfo();
 			if (first_font == our_font)
 				special_case = true;
 		}
@@ -341,7 +341,7 @@ ParagraphList::const_iterator makeParagraphs(Buffer const & buf,
 			// We do not issue the paragraph id if we are doing
 			// this for the TOC (or some similar purpose)
 			openParTag(xs, lay, par->params(),
-			           runparams.for_toc ? "" : par->magicLabel());
+					   runparams.for_toc ? "" : par->magicLabel());
 		}
 
 		docstring const deferred = par->simpleLyXHTMLOnePar(buf, xs,
@@ -385,16 +385,16 @@ ParagraphList::const_iterator makeBibliography(Buffer const & buf,
 bool isNormalEnv(Layout const & lay)
 {
 	return lay.latextype == LATEX_ENVIRONMENT
-	    || lay.latextype == LATEX_BIB_ENVIRONMENT;
+		|| lay.latextype == LATEX_BIB_ENVIRONMENT;
 }
 
 
 ParagraphList::const_iterator makeEnvironment(Buffer const & buf,
-					      XMLStream & xs,
-					      OutputParams const & runparams,
-					      Text const & text,
-					      ParagraphList::const_iterator const & pbegin,
-					      ParagraphList::const_iterator const & pend)
+						  XMLStream & xs,
+						  OutputParams const & runparams,
+						  Text const & text,
+						  ParagraphList::const_iterator const & pbegin,
+						  ParagraphList::const_iterator const & pend)
 {
 	ParagraphList::const_iterator const begin = text.paragraphs().begin();
 	ParagraphList::const_iterator par = pbegin;
@@ -419,7 +419,7 @@ ParagraphList::const_iterator makeEnvironment(Buffer const & buf,
 		Counters & cnts = buf.masterBuffer()->params().documentClass().counters();
 		docstring const & cntr = style.counter;
 		if (!style.counter.empty()
-		    && (par == pbegin || !isNormalEnv(style))
+			&& (par == pbegin || !isNormalEnv(style))
 				&& cnts.hasCounter(cntr)
 		)
 			cnts.step(cntr, OutputUpdate);
@@ -448,7 +448,7 @@ ParagraphList::const_iterator makeEnvironment(Buffer const & buf,
 
 				// label output
 				if (style.labeltype != LABEL_NO_LABEL &&
-				    style.htmllabeltag() != "NONE") {
+					style.htmllabeltag() != "NONE") {
 					if (isNormalEnv(style)) {
 						// in this case, we print the label only for the first
 						// paragraph (as in a theorem).
@@ -542,12 +542,12 @@ void makeCommand(Buffer const & buf,
 	Layout const & style = pbegin->layout();
 	if (!style.counter.empty())
 		buf.masterBuffer()->params().
-		    documentClass().counters().step(style.counter, OutputUpdate);
+			documentClass().counters().step(style.counter, OutputUpdate);
 
 	bool const make_parid = !runparams.for_toc && runparams.html_make_pars;
 
 	openParTag(xs, style, pbegin->params(),
-	           make_parid ? pbegin->magicLabel() : "");
+			   make_parid ? pbegin->magicLabel() : "");
 
 	// Label around sectioning number:
 	// FIXME Probably need to account for LABEL_MANUAL
@@ -571,9 +571,9 @@ void makeCommand(Buffer const & buf,
 
 
 void xhtmlParagraphs(Text const & text,
-		       Buffer const & buf,
-		       XMLStream & xs,
-		       OutputParams const & runparams)
+			   Buffer const & buf,
+			   XMLStream & xs,
+			   OutputParams const & runparams)
 {
 	ParagraphList const & paragraphs = text.paragraphs();
 	if (runparams.par_begin == runparams.par_end) {
@@ -589,6 +589,8 @@ void xhtmlParagraphs(Text const & text,
 	ParagraphList::const_iterator const pend =
 		(epit == (int) paragraphs.size()) ?
 			paragraphs.end() : paragraphs.constIterator(epit);
+	std::stack<int> headerLevels;
+
 	while (bpit < epit) {
 		ParagraphList::const_iterator par = paragraphs.constIterator(bpit);
 		if (par->params().startOfAppendix()) {
@@ -606,6 +608,25 @@ void xhtmlParagraphs(Text const & text,
 		ParagraphList::const_iterator const lastpar = par;
 		ParagraphList::const_iterator send;
 
+		// Think about adding <section> and/or </section>s.
+		if (style.category() == from_utf8("Sectioning")) {
+			// Need to close a previous section if it has the same level or a higher one (close <section> if opening a
+			// <h2> after a <h2>, <h3>, <h4>, <h5> or <h6>). More examples:
+			//   - current: h2; back: h1; do not close any <section>
+			//   - current: h1; back: h2; close two <section> (first the <h2>, then the <h1>, so a new <h1> can come)
+			// The level (h1, h2, etc.) corresponds to style.toclevel.
+			while (! headerLevels.empty() && style.toclevel <= headerLevels.top()) {
+				headerLevels.pop();
+				xs << xml::EndTag("section") << xml::CR();
+			}
+
+			// Open the new one.
+			headerLevels.push(style.toclevel);
+			if (style.toclevel > 1) { // <h1> is the document title.
+				xs << xml::StartTag("section") << xml::CR();
+			}
+		}
+
 		switch (style.latextype) {
 		case LATEX_COMMAND: {
 			// The files with which we are working never have more than
@@ -642,6 +663,13 @@ void xhtmlParagraphs(Text const & text,
 		}
 		bpit += distance(lastpar, par);
 	}
+
+	// If need be, close <section>s, but only at the end of the document (otherwise, dealt with at the beginning
+	// of the loop).
+	while (! headerLevels.empty() && headerLevels.top() > 1) {
+		headerLevels.pop();
+		xs << xml::EndTag("section") << xml::CR();
+	}
 }
 
 
-- 
2.26.1.windows.1

