DocBook: solve issue with formulae within font tags.

This is not valid DocBook either!
This commit is contained in:
Thibaut Cuvelier 2020-07-26 23:23:02 +02:00
parent a874173660
commit 8dd2e7e681
5 changed files with 435 additions and 125 deletions

View File

@ -0,0 +1,266 @@
#LyX 2.4 created this file. For more info see https://www.lyx.org/
\lyxformat 598
\begin_document
\begin_header
\save_transient_properties true
\origin unavailable
\textclass scrartcl
\begin_preamble
% DO NOT ALTER THIS PREAMBLE!!!
%
% This preamble is designed to ensure that the file prints
% out as advertised. If you mess with this preamble,
% parts of this document may not print out as expected. If you
% have problems LaTeXing this file, please contact
% the documentation team
% email: lyx-docs@lists.lyx.org
% solves the following problem:
% If the dection number consits of too many numerals the section heading
% will be printed in the TOC without a space between it and the section number.
% As solution more space between the number and the heading is inserted:
\renewcommand{\l@subsection}{\@dottedtocline{2}{1.5em}{2.8em}}
\renewcommand{\l@subsubsection}{\@dottedtocline{3}{4.3em}{3.6em}}
% increase link area for cross-references and autoname them,
\AtBeginDocument{\renewcommand{\ref}[1]{\mbox{\autoref{#1}}}}
\@ifundefined{extrasenglish}{\usepackage[english]{babel}}{}
\@ifpackageloaded{babel}{
\addto\extrasenglish{%
\renewcommand*{\equationautorefname}[1]{}%
\renewcommand{\sectionautorefname}{sec.\negthinspace}%
\renewcommand{\subsectionautorefname}{sec.\negthinspace}%
\renewcommand{\subsubsectionautorefname}{sec.\negthinspace}%
}
}{}
% don't load packages twice
% see first footnote in sec. 9.3
\@ifundefined{textcolor}{\usepackage{color}}{}
% the pages of the TOC are numbered roman
% and a PDF-bookmark for the TOC is added
\pagenumbering{roman}
\let\myTOC\tableofcontents
\renewcommand{\tableofcontents}{%
\vspace{1cm}
\pdfbookmark[1]{\contentsname}{}
\myTOC
\cleardoublepage
\pagenumbering{arabic}}
% add 0.5 mm vertical space for table rows
\@ifundefined{extrarowheight} {\usepackage{array}}{}
\setlength{\extrarowheight}{0.5mm}
% insert additional vertical space of 1.5 mm between footnotes,
\let\myFoot\footnote
\renewcommand{\footnote}[1]{\myFoot{#1\vspace{1.5mm}}}
% makes caption labels bold
\setkomafont{captionlabel}{\bfseries}
% enables calculation of values
\usepackage{calc}
% for multiple columns used in sec. 24.7
\usepackage{multicol}
% needed in sec. 19.4
\usepackage{remreset}
% for the Fourier transformation symbol
\usepackage{mathrsfs}
% define a color, used in sec.9.3
\definecolor{darkgreen}{cmyk}{0.5, 0, 1, 0.5}
% declare operators (see sec. 10.4 and sec. 15.2)
\DeclareMathOperator*{\Lozenge}{\blacklozenge}
\DeclareMathOperator{\sgn}{sgn}
% example definitions for sec. 20.1
\newcommand{\gr}{\Longrightarrow}
\newcommand{\us}[1]{\underline{#1}}
\newcommand{\fb}[3]{\framebox#1#2{$#3$}}
\newcommand{\cb}[3][white]{\fcolorbox{#2}{#1}{$#3$}}
\newcommand{\fracS}[3][]{\genfrac{}{}{#1}{}{#2}{#3}}
% example macro from sec. 19.4
%\AtBeginDocument{
%\def\tagform@#1{\maketag@@@{|#1|}}
%}
% ------------------------------------
% used to check for needed LaTeX packages
\usepackage{ifthen}
% check for package undertilde
% used for the command \utilde
\newboolean{undertilde}
\IfFileExists{undertilde.sty}
{\usepackage{undertilde}
\setboolean{undertilde}{true}}
{\setboolean{undertilde}{false}}
% check for package eurosym
% used for the Euro symbol
\newboolean{eurosym}
\IfFileExists{eurosym.sty}
{\usepackage[gennarrow]{eurosym}
\setboolean{eurosym}{true}}
{\setboolean{eurosym}{false}}
% check for package braket
% used for physical vectors
\newboolean{braket}
\IfFileExists{braket.sty}
{\usepackage{braket}
\setboolean{braket}{true}}
{\setboolean{braket}{false}}
% check for package cancel
\newboolean{cancel}
\IfFileExists{cancel.sty}
{\usepackage{cancel}
\setboolean{cancel}{true}}
{\setboolean{cancel}{false}}
% check for package upgreek
\newboolean{upgreek}
\IfFileExists{upgreek.sty}
{\usepackage{upgreek}
\setboolean{upgreek}{true}}
{\setboolean{upgreek}{false}}
% Added by lyx2lyx
\setlength{\parskip}{\medskipamount}
\setlength{\parindent}{0pt}
\end_preamble
\options bibliography=totoc,index=totoc,BCOR7.5mm,titlepage,captions=tableheading
\use_default_options false
\begin_modules
subequations
\end_modules
\maintain_unincluded_children no
\language english
\language_package default
\inputencoding utf8
\fontencoding auto
\font_roman "lmodern" "default"
\font_sans "lmss" "default"
\font_typewriter "lmtt" "default"
\font_math "auto" "auto"
\font_default_family default
\use_non_tex_fonts false
\font_sc false
\font_roman_osf false
\font_sans_osf false
\font_typewriter_osf false
\font_sf_scale 100 100
\font_tt_scale 100 100
\use_microtype false
\use_dash_ligatures false
\graphics default
\default_output_format pdf2
\output_sync 0
\bibtex_command default
\index_command makeindex
\paperfontsize 12
\spacing single
\use_hyperref true
\pdf_title "LyX's Math Manual"
\pdf_author "LyX Team, Uwe Stöhr"
\pdf_subject "LyX-documentation about math"
\pdf_keywords "LyX, Mathed"
\pdf_bookmarks true
\pdf_bookmarksnumbered true
\pdf_bookmarksopen true
\pdf_bookmarksopenlevel 1
\pdf_breaklinks false
\pdf_pdfborder false
\pdf_colorlinks true
\pdf_backref false
\pdf_pdfusetitle false
\pdf_quoted_options "linkcolor=black, citecolor=black, urlcolor=blue, filecolor=blue, pdfpagelayout=OneColumn, pdfnewwindow=true, pdfstartview=XYZ, plainpages=false"
\papersize a4
\use_geometry false
\use_package amsmath 2
\use_package amssymb 2
\use_package cancel 1
\use_package esint 1
\use_package mathdots 1
\use_package mathtools 2
\use_package mhchem 1
\use_package stackrel 1
\use_package stmaryrd 1
\use_package undertilde 0
\cite_engine basic
\cite_engine_type default
\biblio_style plain
\use_bibtopic false
\use_indices false
\paperorientation portrait
\suppress_date false
\justification true
\use_refstyle 0
\use_minted 0
\use_lineno 0
\notefontcolor #0000ff
\index Index
\shortcut idx
\color #008000
\end_index
\secnumdepth 4
\tocdepth 3
\paragraph_separation indent
\paragraph_indentation default
\is_math_indent 0
\math_numbering_side default
\quotes_style english
\dynamic_quotes 0
\papercolumns 1
\papersides 2
\paperpagestyle plain
\tablestyle default
\bullet 1 0 6 -1
\bullet 2 2 35 -1
\bullet 3 2 7 -1
\tracking_changes false
\output_changes false
\change_bars false
\postpone_fragile_content false
\html_math_output 0
\html_css_as_file 0
\html_be_strict false
\docbook_table_output 0
\end_header
\begin_body
\begin_layout Title
LyX
\end_layout
\begin_layout Standard
Some text before.
\end_layout
\begin_layout Standard
\series bold
\begin_inset Formula
\[
\cfrac[l]{A}{B+C}\,,\,\cfrac{A}{B+C}\,,\,\cfrac[r]{A}{B+C}
\]
\end_inset
\end_layout
\begin_layout Standard
Some text after.
\end_layout
\end_body
\end_document

View File

@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- This DocBook file was created by LyX 2.4.0dev
See http://www.lyx.org/ for more information -->
<article xml:lang="en_US" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:m="http://www.w3.org/1998/Math/MathML" xmlns:xi="http://www.w3.org/2001/XInclude" version="5.2">
<title>LyX</title>
<para>Some text before.</para>
<informalequation><alt role='tex'>\cfrac[l]{A}{B+C}\,,\,\cfrac{A}{B+C}\,,\,\cfrac[r]{A}{B+C}</alt>
<m:math>
<m:mrow>
<m:mrow>
<m:mfrac>
<m:mrow><m:mi>A</m:mi>
</m:mrow>
<m:mrow>
<m:mrow><m:mi>B</m:mi><m:mo>+</m:mo><m:mi>C</m:mi>
</m:mrow>
</m:mrow>
</m:mfrac><m:mspace width="6px" /><m:mo>,</m:mo><m:mspace width="6px" />
<m:mfrac>
<m:mrow><m:mi>A</m:mi>
</m:mrow>
<m:mrow>
<m:mrow><m:mi>B</m:mi><m:mo>+</m:mo><m:mi>C</m:mi>
</m:mrow>
</m:mrow>
</m:mfrac><m:mspace width="6px" /><m:mo>,</m:mo><m:mspace width="6px" />
<m:mfrac>
<m:mrow><m:mi>A</m:mi>
</m:mrow>
<m:mrow>
<m:mrow><m:mi>B</m:mi><m:mo>+</m:mo><m:mi>C</m:mi>
</m:mrow>
</m:mrow>
</m:mfrac>
</m:mrow>
</m:mrow>
</m:math></informalequation><para>Some text after.</para>
</article>

View File

@ -3156,142 +3156,146 @@ void Paragraph::simpleDocBookOnePar(Buffer const & buf,
Font const font = getFont(buf.masterBuffer()->params(), i, outerfont); Font const font = getFont(buf.masterBuffer()->params(), i, outerfont);
// emphasis if (start_paragraph) {
FontState curstate = font.fontInfo().emph(); // emphasis
if (font_old.emph() != curstate) FontState curstate = font.fontInfo().emph();
doFontSwitchDocBook(tagsToOpen, tagsToClose, emph_flag, curstate, xml::FT_EMPH); if (font_old.emph() != curstate)
doFontSwitchDocBook(tagsToOpen, tagsToClose, emph_flag, curstate, xml::FT_EMPH);
// noun // noun
curstate = font.fontInfo().noun(); curstate = font.fontInfo().noun();
if (font_old.noun() != curstate) if (font_old.noun() != curstate)
doFontSwitchDocBook(tagsToOpen, tagsToClose, noun_flag, curstate, xml::FT_NOUN); doFontSwitchDocBook(tagsToOpen, tagsToClose, noun_flag, curstate, xml::FT_NOUN);
// underbar // underbar
curstate = font.fontInfo().underbar(); curstate = font.fontInfo().underbar();
if (font_old.underbar() != curstate) if (font_old.underbar() != curstate)
doFontSwitchDocBook(tagsToOpen, tagsToClose, ubar_flag, curstate, xml::FT_UBAR); doFontSwitchDocBook(tagsToOpen, tagsToClose, ubar_flag, curstate, xml::FT_UBAR);
// strikeout // strikeout
curstate = font.fontInfo().strikeout(); curstate = font.fontInfo().strikeout();
if (font_old.strikeout() != curstate) if (font_old.strikeout() != curstate)
doFontSwitchDocBook(tagsToOpen, tagsToClose, sout_flag, curstate, xml::FT_SOUT); doFontSwitchDocBook(tagsToOpen, tagsToClose, sout_flag, curstate, xml::FT_SOUT);
// double underbar // double underbar
curstate = font.fontInfo().uuline(); curstate = font.fontInfo().uuline();
if (font_old.uuline() != curstate) if (font_old.uuline() != curstate)
doFontSwitchDocBook(tagsToOpen, tagsToClose, dbar_flag, curstate, xml::FT_DBAR); doFontSwitchDocBook(tagsToOpen, tagsToClose, dbar_flag, curstate, xml::FT_DBAR);
// wavy line // wavy line
curstate = font.fontInfo().uwave(); curstate = font.fontInfo().uwave();
if (font_old.uwave() != curstate) if (font_old.uwave() != curstate)
doFontSwitchDocBook(tagsToOpen, tagsToClose, wave_flag, curstate, xml::FT_WAVE); doFontSwitchDocBook(tagsToOpen, tagsToClose, wave_flag, curstate, xml::FT_WAVE);
// bold // bold
// a little hackish, but allows us to reuse what we have. // a little hackish, but allows us to reuse what we have.
curstate = (font.fontInfo().series() == BOLD_SERIES ? FONT_ON : FONT_OFF); curstate = (font.fontInfo().series() == BOLD_SERIES ? FONT_ON : FONT_OFF);
if (font_old.series() != font.fontInfo().series()) if (font_old.series() != font.fontInfo().series())
doFontSwitchDocBook(tagsToOpen, tagsToClose, bold_flag, curstate, xml::FT_BOLD); doFontSwitchDocBook(tagsToOpen, tagsToClose, bold_flag, curstate, xml::FT_BOLD);
// Font shape // Font shape
curr_fs = font.fontInfo().shape(); curr_fs = font.fontInfo().shape();
FontShape old_fs = font_old.shape(); FontShape old_fs = font_old.shape();
if (old_fs != curr_fs) { if (old_fs != curr_fs) {
if (shap_flag) { if (shap_flag) {
OptionalFontType tag = fontShapeToXml(old_fs); OptionalFontType tag = fontShapeToXml(old_fs);
if (tag.has_value) {
tagsToClose.push_back(docbookEndFontTag(tag.ft));
}
shap_flag = false;
}
OptionalFontType tag = fontShapeToXml(curr_fs);
if (tag.has_value) { if (tag.has_value) {
tagsToClose.push_back(docbookEndFontTag(tag.ft)); tagsToOpen.push_back(docbookStartFontTag(tag.ft));
} }
shap_flag = false;
} }
OptionalFontType tag = fontShapeToXml(curr_fs); // Font family
if (tag.has_value) { curr_fam = font.fontInfo().family();
tagsToOpen.push_back(docbookStartFontTag(tag.ft)); FontFamily old_fam = font_old.family();
if (old_fam != curr_fam) {
if (faml_flag) {
OptionalFontType tag = fontFamilyToXml(old_fam);
if (tag.has_value) {
tagsToClose.push_back(docbookEndFontTag(tag.ft));
}
faml_flag = false;
}
switch (curr_fam) {
case ROMAN_FAMILY:
// we will treat a "default" font family as roman, since we have
// no other idea what to do.
if (default_family != "rmdefault" && default_family != "default") {
tagsToOpen.push_back(docbookStartFontTag(xml::FT_ROMAN));
faml_flag = true;
}
break;
case SANS_FAMILY:
if (default_family != "sfdefault") {
tagsToOpen.push_back(docbookStartFontTag(xml::FT_SANS));
faml_flag = true;
}
break;
case TYPEWRITER_FAMILY:
if (default_family != "ttdefault") {
tagsToOpen.push_back(docbookStartFontTag(xml::FT_TYPE));
faml_flag = true;
}
break;
case INHERIT_FAMILY:
break;
default:
// the other tags are for internal use
LATTEST(false);
break;
}
} }
}
// Font family // Font size
curr_fam = font.fontInfo().family(); curr_size = font.fontInfo().size();
FontFamily old_fam = font_old.family(); FontSize old_size = font_old.size();
if (old_fam != curr_fam) { if (old_size != curr_size) {
if (faml_flag) { if (size_flag) {
OptionalFontType tag = fontFamilyToXml(old_fam); OptionalFontType tag = fontSizeToXml(old_size);
if (tag.has_value) {
tagsToClose.push_back(docbookEndFontTag(tag.ft));
}
size_flag = false;
}
OptionalFontType tag = fontSizeToXml(curr_size);
if (tag.has_value) { if (tag.has_value) {
tagsToClose.push_back(docbookEndFontTag(tag.ft)); tagsToOpen.push_back(docbookStartFontTag(tag.ft));
size_flag = true;
} }
faml_flag = false;
}
switch (curr_fam) {
case ROMAN_FAMILY:
// we will treat a "default" font family as roman, since we have
// no other idea what to do.
if (default_family != "rmdefault" && default_family != "default") {
tagsToOpen.push_back(docbookStartFontTag(xml::FT_ROMAN));
faml_flag = true;
}
break;
case SANS_FAMILY:
if (default_family != "sfdefault") {
tagsToOpen.push_back(docbookStartFontTag(xml::FT_SANS));
faml_flag = true;
}
break;
case TYPEWRITER_FAMILY:
if (default_family != "ttdefault") {
tagsToOpen.push_back(docbookStartFontTag(xml::FT_TYPE));
faml_flag = true;
}
break;
case INHERIT_FAMILY:
break;
default:
// the other tags are for internal use
LATTEST(false);
break;
} }
// FIXME XHTML
// Other such tags? What about the other text ranges?
vector<xml::EndFontTag>::const_iterator cit = tagsToClose.begin();
vector<xml::EndFontTag>::const_iterator cen = tagsToClose.end();
for (; cit != cen; ++cit)
xs << *cit;
vector<xml::FontTag>::const_iterator sit = tagsToOpen.begin();
vector<xml::FontTag>::const_iterator sen = tagsToOpen.end();
for (; sit != sen; ++sit)
xs << *sit;
tagsToClose.clear();
tagsToOpen.clear();
} }
// Font size
curr_size = font.fontInfo().size();
FontSize old_size = font_old.size();
if (old_size != curr_size) {
if (size_flag) {
OptionalFontType tag = fontSizeToXml(old_size);
if (tag.has_value) {
tagsToClose.push_back(docbookEndFontTag(tag.ft));
}
size_flag = false;
}
OptionalFontType tag = fontSizeToXml(curr_size);
if (tag.has_value) {
tagsToOpen.push_back(docbookStartFontTag(tag.ft));
size_flag = true;
}
}
// FIXME XHTML
// Other such tags? What about the other text ranges?
vector<xml::EndFontTag>::const_iterator cit = tagsToClose.begin();
vector<xml::EndFontTag>::const_iterator cen = tagsToClose.end();
for (; cit != cen; ++cit)
xs << *cit;
vector<xml::FontTag>::const_iterator sit = tagsToOpen.begin();
vector<xml::FontTag>::const_iterator sen = tagsToOpen.end();
for (; sit != sen; ++sit)
xs << *sit;
tagsToClose.clear();
tagsToOpen.clear();
if (Inset const * inset = getInset(i)) { if (Inset const * inset = getInset(i)) {
if (!runparams.for_toc || inset->isInToc()) { if (!runparams.for_toc || inset->isInToc()) {
OutputParams np = runparams; OutputParams np = runparams;
np.local_font = &font; np.local_font = &font;
// If the paragraph has size 1, then we are in the "special // If the paragraph has size 1, then we are in the "special
// case" where we do not output the containing paragraph info. // case" where we do not output the containing paragraph info.
// This "special case" is defined in more details in output_docbook.cpp, makeParagraphs. The results
// of that brittle logic is passed to this function through open_par.
if (!inset->getLayout().htmlisblock() && size() != 1) // TODO: htmlisblock here too! if (!inset->getLayout().htmlisblock() && size() != 1) // TODO: htmlisblock here too!
np.docbook_in_par = true; np.docbook_in_par = true;
inset->docbook(xs, np); inset->docbook(xs, np);

View File

@ -2406,11 +2406,6 @@ int InsetMathHull::plaintext(odocstringstream & os,
void InsetMathHull::docbook(XMLStream & xs, OutputParams const & runparams) const void InsetMathHull::docbook(XMLStream & xs, OutputParams const & runparams) const
{ {
// With DocBook 5, MathML must be within its own namespace; defined in Buffer.cpp::writeDocBookSource as "m".
// Output everything in a separate stream so that this does not interfere with the standard flow of DocBook tags.
odocstringstream osmath;
MathStream ms(osmath, "m", true);
// Choose the tag around the MathML equation. // Choose the tag around the MathML equation.
docstring name; docstring name;
if (getType() == hullSimple) if (getType() == hullSimple)
@ -2420,15 +2415,20 @@ void InsetMathHull::docbook(XMLStream & xs, OutputParams const & runparams) cons
// DocBook also has <equation>, but it comes with a title. // DocBook also has <equation>, but it comes with a title.
docstring bname = name; docstring attr;
for (row_type i = 0; i < nrows(); ++i) { for (row_type i = 0; i < nrows(); ++i) {
if (!label(i).empty()) { if (!label(i).empty()) {
bname += " xml:id=\"" + xml::cleanID(label(i)) + "\""; attr = "xml:id=\"" + xml::cleanID(label(i)) + "\"";
break; break;
} }
} }
++ms.tab(); ms.cr(); ms.os() << '<' << bname << '>'; xs << xml::StartTag(name, attr);
// With DocBook 5, MathML must be within its own namespace; defined in Buffer.cpp::writeDocBookSource as "m".
// Output everything in a separate stream so that this does not interfere with the standard flow of DocBook tags.
odocstringstream osmath;
MathStream ms(osmath, "m", true);
// Output the MathML subtree. // Output the MathML subtree.
odocstringstream ls; odocstringstream ls;
@ -2463,11 +2463,9 @@ void InsetMathHull::docbook(XMLStream & xs, OutputParams const & runparams) cons
osmath << "MathML export failed. Please report this as a bug."; osmath << "MathML export failed. Please report this as a bug.";
} }
// Close the DocBook tag enclosing the formula. // Output the complete formula to the DocBook stream.
ms.cr(); --ms.tab(); ms.os() << "</" << name << '>';
// Output the complete tag to the DocBook stream.
xs << XMLStream::ESCAPE_NONE << osmath.str(); xs << XMLStream::ESCAPE_NONE << osmath.str();
xs << xml::EndTag(name);
} }

View File

@ -185,7 +185,9 @@ bool XMLStream::closeFontTags() {
tag_stack_.pop_back(); tag_stack_.pop_back();
// this shouldn't happen, since then the font tags // this shouldn't happen, since then the font tags
// weren't in any other tag. // weren't in any other tag.
LASSERT(!tag_stack_.empty(), return true); // LASSERT(!tag_stack_.empty(), return true);
if (tag_stack_.empty())
return true;
curtag = &tag_stack_.back(); curtag = &tag_stack_.back();
} }