]> git.lyx.org Git - lyx.git/blobdiff - src/insets/InsetTabular.cpp
Fix bug #12795
[lyx.git] / src / insets / InsetTabular.cpp
index e2529a9fd0abe03b3ba1aefb0e370c26f5d4905d..69f9e73e59f0f0f11e125f2c80e4ba5449048455 100644 (file)
@@ -3007,7 +3007,7 @@ void Tabular::TeXCellPreamble(otexstream & os, idx_type cell,
                   << "}\n";
        } else if (getUsebox(cell) == BOX_VARWIDTH
                   && (getRotateCell(cell) != 0 || align != LYX_ALIGN_LEFT
-                      || valign != LYX_VALIGN_TOP)) {
+                      || valign != LYX_VALIGN_TOP || hasNewlines(cell))) {
                os << "\\begin{cellvarwidth}[";
                switch (valign) {
                case LYX_VALIGN_TOP:
@@ -3056,7 +3056,7 @@ void Tabular::TeXCellPostamble(otexstream & os, idx_type cell,
                os << breakln << "\\end{minipage}";
        else if (getUsebox(cell) == BOX_VARWIDTH
                 && (getRotateCell(cell) != 0 || getAlignment(cell) != LYX_ALIGN_LEFT
-                    || getVAlignment(cell) != LYX_VALIGN_TOP))
+                    || getVAlignment(cell) != LYX_VALIGN_TOP || hasNewlines(cell)))
                os << breakln << "\\end{cellvarwidth}";
        if (getRotateCell(cell) != 0)
                os << breakln << "\\end{turn}";
@@ -3208,7 +3208,7 @@ void Tabular::TeXRow(otexstream & os, row_type row,
                bool rtl = par.isRTL(buffer().params())
                        && !par.empty()
                        && getPWidth(cell).zero()
-                       && !runparams.use_polyglossia;
+                       && !runparams.isFullUnicode();
 
                if (rtl) {
                        string const lang =
@@ -3272,7 +3272,7 @@ void Tabular::TeXRow(otexstream & os, row_type row,
                } else if (!isPartOfMultiRow(row, c)) {
                        if (!runparams.nice)
                                os.texrow().start(par.id(), 0);
-                       if (isMultiRow(cell) && !LaTeXFeatures::isAvailable("multirow-2021/01/29"))
+                       if (isMultiRow(cell) && !LaTeXFeatures::isAvailableAtLeastFrom("multirow", 2021, 1, 29))
                                newrp.isNonLong = true;
                        inset->latex(os, newrp);
                }
@@ -3628,31 +3628,63 @@ std::string Tabular::getVAlignAsXmlAttribute(idx_type cell) const
 }
 
 
-std::string Tabular::getHAlignAsXmlAttribute(idx_type cell, const XmlOutputFormat output_format) const
+std::string Tabular::getVAlignAsCssAttribute(idx_type cell) const
+{
+       switch (getVAlignment(cell)) {
+       case LYX_VALIGN_TOP:
+               return "vertical-align: top";
+       case LYX_VALIGN_BOTTOM:
+               return "vertical-align: bottom";
+       case LYX_VALIGN_MIDDLE:
+               return "vertical-align: middle";
+       default:
+               // This case only silences a compiler warning, as all the cases are covered above.
+               return "";
+       }
+}
+
+
+std::string Tabular::getHAlignAsXmlAttribute(idx_type cell) const
 {
        switch (getAlignment(cell)) {
        case LYX_ALIGN_LEFT:
                return "align='left'";
        case LYX_ALIGN_RIGHT:
                return "align='right'";
+       case LYX_ALIGN_BLOCK:
+               return "align='justify'";
+       case LYX_ALIGN_DECIMAL: {
+               Language const *lang = buffer().paragraphs().front().getParLanguage(buffer().params());
+               return "align='char' char='" + to_utf8(lang->decimalSeparator()) + "'";
+       }
+       default:
+               return "align='center'";
+       }
+}
+
 
+std::string Tabular::getHAlignAsCssAttribute(idx_type cell) const
+{
+       switch (getAlignment(cell)) {
+       case LYX_ALIGN_LEFT:
+               return "text-align: left";
+       case LYX_ALIGN_RIGHT:
+               return "text-align: right";
+       case LYX_ALIGN_BLOCK:
+               return "text-align: justify";
+       case LYX_ALIGN_DECIMAL: {
+               // In theory, character-level alignment is supported for CSS4, but it's
+               // experimental.
+               // https://www.w3.org/TR/css-text-4/#character-alignment
+               Language const *lang = buffer().paragraphs().front().getParLanguage(buffer().params());
+               return "text-align: \"" + to_utf8(lang->decimalSeparator()) + "\"";
+       }
        default:
-               // HTML only supports left, right, and center.
-               if (output_format == XmlOutputFormat::XHTML)
-                       return "align='center'";
-
-               // DocBook also has justify and decimal.
-               if (getAlignment(cell) == LYX_ALIGN_BLOCK) {
-                       return "align='justify'";
-               } else if (getAlignment(cell) == LYX_ALIGN_DECIMAL) {
-                       Language const *tlang = buffer().paragraphs().front().getParLanguage(buffer().params());
-                       return "align='char' char='" + to_utf8(tlang->decimalSeparator()) + "'";
-               } else {
-                       return "align='center'";
-               }
+               return "text-align: center";
        }
 }
 
+
 Tabular::XmlRowWiseBorders Tabular::computeXmlBorders(row_type row) const
 {
        Tabular::XmlRowWiseBorders borders;
@@ -3755,25 +3787,24 @@ docstring Tabular::xmlRow(XMLStream & xs, const row_type row, OutputParams const
                if (isPartOfMultiColumn(row, c) || isPartOfMultiRow(row, c))
                        continue;
 
-               stringstream attr;
-
-               if (is_xhtml_table) {
-                       const std::vector<std::string> styles = computeCssStylePerCell(row, c, cell);
-                       attr << "style='" ;
-               for (auto it = styles.begin(); it != styles.end(); ++it) {
-                               attr << *it;
-                               if (it != styles.end() - 1)
-                                       attr << "; ";
-               }
-                       attr << "' ";
-               }
+               stringstream attr; // Tag-level attributes, both for HTML and CALS.
+               stringstream style; // Tag-level CSS, only for HTML tables output in HTML.
 
                if (is_cals_table) {
                        if (!cals_row_has_rowsep && bottomLine(cell))
                                attr << "rowsep='1' ";
                }
 
-               attr << getHAlignAsXmlAttribute(cell, output_format) << " " << getVAlignAsXmlAttribute(cell);
+               if (output_format == XmlOutputFormat::XHTML) {
+                       // In HTML5, prefer to use CSS instead of attributes for alignment
+                       // (align and valign).
+                       style << getHAlignAsCssAttribute(cell) << "; "
+                             << getVAlignAsCssAttribute(cell);
+               } else {
+                       // In DocBook, both for HTML and CALS tables, stick to attributes.
+                       attr << getHAlignAsXmlAttribute(cell) << " "
+                            << getVAlignAsXmlAttribute(cell);
+               }
 
                if (is_xhtml_table) {
                        if (isMultiColumn(cell))
@@ -3789,8 +3820,26 @@ docstring Tabular::xmlRow(XMLStream & xs, const row_type row, OutputParams const
                                attr << " colname='c" << (c + 1) << "'"; // CALS column numbering starts at 1.
                }
 
+               // Final step: prepend the CSS style.
+               std::string attr_str = attr.str();
+               if (is_xhtml_table) {
+                       const std::vector<std::string> styles = computeCssStylePerCell(row, c, cell);
+
+                       std::string attr_str_prefix = "style='" + style.str();
+                       if (!styles.empty())
+                               attr_str_prefix += "; ";
+                       for (auto it = styles.begin(); it != styles.end(); ++it) {
+                               attr_str_prefix += *it;
+                               if (it != styles.end() - 1)
+                                       attr_str_prefix += "; ";
+                       }
+                       attr_str_prefix += "' ";
+
+                       attr_str.insert(0, attr_str_prefix);
+               }
+
                // Render the cell as either XHTML or DocBook.
-               xs << xml::StartTag(cell_tag, attr.str(), true);
+               xs << xml::StartTag(cell_tag, attr_str, true);
                if (output_format == XmlOutputFormat::XHTML) {
                        ret += cellInset(cell)->xhtml(xs, runparams);
                } else if (output_format == XmlOutputFormat::DOCBOOK) {
@@ -4272,6 +4321,21 @@ Tabular::BoxType Tabular::useBox(idx_type cell) const
 }
 
 
+bool Tabular::hasNewlines(idx_type cell) const
+{
+       ParagraphList const & parlist = cellInset(cell)->paragraphs();
+       ParagraphList::const_iterator cit = parlist.begin();
+       ParagraphList::const_iterator end = parlist.end();
+
+       for (; cit != end; ++cit)
+               for (int i = 0; i < cit->size(); ++i)
+                       if (cit->isNewline(i))
+                               return true;
+
+       return false;
+}
+
+
 /////////////////////////////////////////////////////////////////////
 //
 // InsetTableCell
@@ -7452,10 +7516,15 @@ docstring InsetTabular::asString(idx_type stidx, idx_type enidx,
 {
        LASSERT(stidx <= enidx, return docstring());
        docstring retval;
-       col_type const col1 = tabular.cellColumn(stidx);
-       col_type const col2 = tabular.cellColumn(enidx);
-       row_type const row1 = tabular.cellRow(stidx);
-       row_type const row2 = tabular.cellRow(enidx);
+       col_type col1 = tabular.cellColumn(stidx);
+       col_type col2 = tabular.cellColumn(enidx);
+       row_type row1 = tabular.cellRow(stidx);
+       row_type row2 = tabular.cellRow(enidx);
+       // stidx might be in a later column or row than enidx
+       if (col1 > col2)
+               swap(col1, col2);
+       if (row1 > row2)
+               swap(row1, row2);
        bool first = true;
        for (col_type col = col1; col <= col2; col++)
                for (row_type row = row1; row <= row2; row++) {
@@ -7473,10 +7542,15 @@ ParagraphList InsetTabular::asParList(idx_type stidx, idx_type enidx)
 {
        LASSERT(stidx <= enidx, return ParagraphList());
        ParagraphList retval;
-       col_type const col1 = tabular.cellColumn(stidx);
-       col_type const col2 = tabular.cellColumn(enidx);
-       row_type const row1 = tabular.cellRow(stidx);
-       row_type const row2 = tabular.cellRow(enidx);
+       col_type col1 = tabular.cellColumn(stidx);
+       col_type col2 = tabular.cellColumn(enidx);
+       row_type row1 = tabular.cellRow(stidx);
+       row_type row2 = tabular.cellRow(enidx);
+       // stidx might be in a later column or row than enidx
+       if (col1 > col2)
+               swap(col1, col2);
+       if (row1 > row2)
+               swap(row1, row2);
        for (col_type col = col1; col <= col2; col++)
                for (row_type row = row1; row <= row2; row++)
                        for (auto const & par : tabular.cellInset(row, col)->paragraphs())