X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2FParagraph.cpp;h=e497a85ae60e3672baa1426c839727d9854ee8ed;hb=28be7d552f62cc02fa86d7f79201d089bfb2d7b5;hp=aea3234a19ced0765cffa75e1597867e97756304;hpb=7cf12243b87b8d3e24a46dfc18af1013fa4ea0ba;p=lyx.git diff --git a/src/Paragraph.cpp b/src/Paragraph.cpp index aea3234a19..e497a85ae6 100644 --- a/src/Paragraph.cpp +++ b/src/Paragraph.cpp @@ -52,6 +52,7 @@ #include "insets/InsetBibitem.h" #include "insets/InsetLabel.h" #include "insets/InsetSpecialChar.h" +#include "insets/InsetText.h" #include "mathed/InsetMathHull.h" @@ -70,6 +71,15 @@ using namespace std; using namespace lyx::support; +// OSX clang, gcc < 4.8.0, and msvc < 2015 do not support C++11 thread_local +#if defined(__APPLE__) || (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ < 8) +#define THREAD_LOCAL_STATIC static __thread +#elif defined(_MSC_VER) && (_MSC_VER < 1900) +#define THREAD_LOCAL_STATIC static __declspec(thread) +#else +#define THREAD_LOCAL_STATIC thread_local static +#endif + namespace lyx { namespace { @@ -363,6 +373,12 @@ public: pos_type i, unsigned int & column); /// + bool latexSpecialTU( + char_type const c, + otexstream & os, + pos_type i, + unsigned int & column); + /// bool latexSpecialT3( char_type const c, otexstream & os, @@ -562,10 +578,10 @@ Paragraph::Private::Private(Private const & p, Paragraph * owner, } -void Paragraph::addChangesToToc(DocIterator const & cdit, - Buffer const & buf, bool output_active) const +void Paragraph::addChangesToToc(DocIterator const & cdit, Buffer const & buf, + bool output_active, TocBackend & backend) const { - d->changes_.addToToc(cdit, buf, output_active); + d->changes_.addToToc(cdit, buf, output_active, backend); } @@ -1038,9 +1054,10 @@ void Paragraph::Private::latexInset(BufferParams const & bparams, os << '\n'; } else { if (open_font) { + bool needPar = false; column += running_font.latexWriteEndChanges( os, bparams, runparams, - basefont, basefont); + basefont, basefont, needPar); open_font = false; } @@ -1079,7 +1096,7 @@ void Paragraph::Private::latexInset(BufferParams const & bparams, // decorations at all && inset->lyxCode() != ERT_CODE) { if (running_font.language()->lang() == "farsi") - os << "\\beginL{}"; + os << "\\beginL" << termcmd; else os << "\\L{"; close = true; @@ -1098,10 +1115,12 @@ void Paragraph::Private::latexInset(BufferParams const & bparams, bool arabtex = basefont.language()->lang() == "arabic_arabtex" || running_font.language()->lang() == "arabic_arabtex"; if (open_font && !inset->inheritFont()) { + bool needPar = false; bool closeLanguage = arabtex || basefont.isRightToLeft() == running_font.isRightToLeft(); unsigned int count = running_font.latexWriteEndChanges(os, - bparams, runparams, basefont, basefont, closeLanguage); + bparams, runparams, basefont, basefont, + needPar, closeLanguage); column += count; // if any font properties were closed, update the running_font, // making sure, however, to leave the language as it was @@ -1135,7 +1154,7 @@ void Paragraph::Private::latexInset(BufferParams const & bparams, if (close) { if (running_font.language()->lang() == "farsi") - os << "\\endL{}"; + os << "\\endL" << termcmd; else os << '}'; } @@ -1188,25 +1207,30 @@ void Paragraph::Private::latexSpecialChar(otexstream & os, // non-standard font encoding. If we are using such a language, // we do not output special T1 chars. if (!runparams.inIPA && !running_font.language()->internalFontEncoding() - && bparams.font_encoding() == "T1" && latexSpecialT1(c, os, i, column)) + && !runparams.isFullUnicode() && bparams.main_font_encoding() == "T1" + && latexSpecialT1(c, os, i, column)) return; + // NOTE: XeTeX and LuaTeX use EU1/2 (pre 2017) or TU (as of 2017) encoding + else if (!runparams.inIPA && !running_font.language()->internalFontEncoding() + && runparams.isFullUnicode() && latexSpecialTU(c, os, i, column)) + return; // Otherwise, we use what LaTeX provides us. switch (c) { case '\\': - os << "\\textbackslash{}"; + os << "\\textbackslash" << termcmd; column += 15; break; case '<': - os << "\\textless{}"; + os << "\\textless" << termcmd; column += 10; break; case '>': - os << "\\textgreater{}"; + os << "\\textgreater" << termcmd; column += 13; break; case '|': - os << "\\textbar{}"; + os << "\\textbar" << termcmd; column += 9; break; case '-': @@ -1223,7 +1247,7 @@ void Paragraph::Private::latexSpecialChar(otexstream & os, } break; case '\"': - os << "\\char`\\\"{}"; + os << "\\char34" << termcmd; column += 9; break; @@ -1236,12 +1260,12 @@ void Paragraph::Private::latexSpecialChar(otexstream & os, break; case '~': - os << "\\textasciitilde{}"; + os << "\\textasciitilde" << termcmd; column += 16; break; case '^': - os << "\\textasciicircum{}"; + os << "\\textasciicircum" << termcmd; column += 17; break; @@ -1263,6 +1287,21 @@ void Paragraph::Private::latexSpecialChar(otexstream & os, // written. (Asger) break; + case 0x2013: + case 0x2014: + if (bparams.use_dash_ligatures && !bparams.useNonTeXFonts) { + if (c == 0x2013) { + // en-dash + os << "--"; + column +=2; + } else { + // em-dash + os << "---"; + column +=3; + } + break; + } + // fall through default: if (c == '\0') return; @@ -1339,7 +1378,7 @@ bool Paragraph::Private::latexSpecialT1(char_type const c, otexstream & os, // but we should avoid ligatures if (i + 1 >= int(text_.size()) || text_[i + 1] != c) return true; - os << "\\textcompwordmark{}"; + os << "\\textcompwordmark" << termcmd; column += 19; return true; case '|': @@ -1347,7 +1386,7 @@ bool Paragraph::Private::latexSpecialT1(char_type const c, otexstream & os, return true; case '\"': // soul.sty breaks with \char`\" - os << "\\textquotedbl{}"; + os << "\\textquotedbl" << termcmd; column += 14; return true; default: @@ -1356,6 +1395,14 @@ bool Paragraph::Private::latexSpecialT1(char_type const c, otexstream & os, } +bool Paragraph::Private::latexSpecialTU(char_type const c, otexstream & os, + pos_type i, unsigned int & column) +{ + // TU encoding is currently on par with T1. + return latexSpecialT1(c, os, i, column); +} + + bool Paragraph::Private::latexSpecialT3(char_type const c, otexstream & os, pos_type /*i*/, unsigned int & column) { @@ -1367,7 +1414,7 @@ bool Paragraph::Private::latexSpecialT3(char_type const c, otexstream & os, os.put(c); return true; case '|': - os << "\\textvertline{}"; + os << "\\textvertline" << termcmd; column += 14; return true; default: @@ -1389,6 +1436,7 @@ void Paragraph::Private::validate(LaTeXFeatures & features) const // output is wrong if this paragraph contains content // that needs to switch encoding. otexstringstream os; + os << layout_->preamble(); if (is_command) { os << '\\' << from_ascii(layout_->latexname()); // we have to provide all the optional arguments here, even though @@ -1948,7 +1996,7 @@ depth_type Paragraph::getMaxDepthAfter() const } -char Paragraph::getAlign() const +LyXAlignment Paragraph::getAlign() const { if (d->params_.align() == LYX_ALIGN_LAYOUT) return d->layout_->align; @@ -2353,14 +2401,19 @@ void Paragraph::latex(BufferParams const & bparams, column += d->startTeXParParams(bparams, os, runparams); } + // Whether a \par can be issued for insets typeset inline with text. + // Yes if greater than 0. This has to be static. + THREAD_LOCAL_STATIC int parInline = 0; + for (pos_type i = 0; i < size(); ++i) { // First char in paragraph or after label? if (i == body_pos) { if (body_pos > 0) { if (open_font) { + bool needPar = false; column += running_font.latexWriteEndChanges( os, bparams, runparams, - basefont, basefont); + basefont, basefont, needPar); open_font = false; } basefont = getLayoutFont(bparams, outerfont); @@ -2389,6 +2442,7 @@ void Paragraph::latex(BufferParams const & bparams, runparams); } + runparams.wasDisplayMath = runparams.inDisplayMath; runparams.inDisplayMath = false; bool deleted_display_math = false; @@ -2412,8 +2466,10 @@ void Paragraph::latex(BufferParams const & bparams, if (bparams.output_changes && runningChange != change) { if (open_font) { + bool needPar = false; column += running_font.latexWriteEndChanges( - os, bparams, runparams, basefont, basefont); + os, bparams, runparams, + basefont, basefont, needPar); open_font = false; } basefont = getLayoutFont(bparams, outerfont); @@ -2441,9 +2497,11 @@ void Paragraph::latex(BufferParams const & bparams, (current_font != running_font || current_font.language() != running_font.language())) { + bool needPar = false; column += running_font.latexWriteEndChanges( - os, bparams, runparams, basefont, - (i == body_pos-1) ? basefont : current_font); + os, bparams, runparams, basefont, + (i == body_pos-1) ? basefont : current_font, + needPar); running_font = basefont; open_font = false; } @@ -2453,6 +2511,8 @@ void Paragraph::latex(BufferParams const & bparams, // close babel's font environment before opening CJK. string const lang_end_command = runparams.use_polyglossia ? "\\end{$$lang}" : lyxrc.language_command_end; + bool const using_begin_end = runparams.use_polyglossia || + !lang_end_command.empty(); if (!running_lang.empty() && current_font.language()->encoding()->package() == Encoding::CJK) { string end_tag = subst(lang_end_command, @@ -2460,8 +2520,8 @@ void Paragraph::latex(BufferParams const & bparams, running_lang); os << from_ascii(end_tag); column += end_tag.length(); - if (runparams.use_polyglossia) - popPolyglossiaLang(); + if (using_begin_end) + popLanguageName(); } // Switch file encoding if necessary (and allowed) @@ -2557,9 +2617,40 @@ void Paragraph::latex(BufferParams const & bparams, // and then split to handle the two modes separately. if (c == META_INSET) { if (i >= start_pos && (end_pos == -1 || i < end_pos)) { + // Greyedout notes and, in general, all insets + // with InsetLayout::isDisplay() == false, + // are typeset inline with the text. So, we + // can add a \par to the last paragraph of + // such insets only if nothing else follows. + bool incremented = false; + Inset const * inset = getInset(i); + InsetText const * textinset = inset + ? inset->asInsetText() + : 0; + if (i + 1 == size() && textinset + && !inset->getLayout().isDisplay()) { + ParagraphList const & pars = + textinset->text().paragraphs(); + pit_type const pit = pars.size() - 1; + Font const last_font = + pit < 0 || pars[pit].empty() + ? pars[pit].getLayoutFont( + bparams, + outerfont) + : pars[pit].getFont(bparams, + pars[pit].size() - 1, + outerfont); + if (last_font.fontInfo().size() != + basefont.fontInfo().size()) { + ++parInline; + incremented = true; + } + } d->latexInset(bparams, os, rp, running_font, basefont, outerfont, open_font, runningChange, style, i, column); + if (incremented) + --parInline; } } else if (i >= start_pos && (end_pos == -1 || i < end_pos)) { try { @@ -2593,22 +2684,62 @@ void Paragraph::latex(BufferParams const & bparams, // If we have an open font definition, we have to close it if (open_font) { + // Make sure that \\par is done with the font of the last + // character if this has another size as the default. + // This is necessary because LaTeX (and LyX on the screen) + // calculates the space between the baselines according + // to this font. (Matthias) + // + // We must not change the font for the last paragraph + // of non-multipar insets, tabular cells or commands, + // since this produces unwanted whitespace. + + Font const font = empty() + ? getLayoutFont(bparams, outerfont) + : getFont(bparams, size() - 1, outerfont); + + InsetText const * textinset = inInset().asInsetText(); + + bool const maintext = textinset + ? textinset->text().isMainText() + : false; + + size_t const numpars = textinset + ? textinset->text().paragraphs().size() + : 0; + + bool needPar = false; + + if (style.resfont.size() != font.fontInfo().size() + && (!runparams.isLastPar || maintext + || (numpars > 1 && d->ownerCode() != CELL_CODE + && (inInset().getLayout().isDisplay() + || parInline))) + && !style.isCommand()) { + needPar = true; + } #ifdef FIXED_LANGUAGE_END_DETECTION if (next_) { running_font.latexWriteEndChanges(os, bparams, runparams, basefont, - next_->getFont(bparams, 0, outerfont)); + next_->getFont(bparams, 0, outerfont), + needPar); } else { running_font.latexWriteEndChanges(os, bparams, - runparams, basefont, basefont); + runparams, basefont, basefont, needPar); } #else //FIXME: For now we ALWAYS have to close the foreign font settings if they are //FIXME: there as we start another \selectlanguage with the next paragraph if //FIXME: we are in need of this. This should be fixed sometime (Jug) running_font.latexWriteEndChanges(os, bparams, runparams, - basefont, basefont); + basefont, basefont, needPar); #endif + if (needPar) { + // The \par could not be inserted at the same nesting + // level of the font size change, so do it now. + os << "{\\" << font.latexSize() << "\\par}"; + } } column += Changes::latexMarkChange(os, bparams, runningChange, @@ -2816,6 +2947,7 @@ docstring Paragraph::simpleLyXHTMLOnePar(Buffer const & buf, bool ubar_flag = false; bool dbar_flag = false; bool sout_flag = false; + bool xout_flag = false; bool wave_flag = false; // shape tags bool shap_flag = false; @@ -2870,6 +3002,11 @@ docstring Paragraph::simpleLyXHTMLOnePar(Buffer const & buf, if (font_old.strikeout() != curstate) doFontSwitch(tagsToOpen, tagsToClose, sout_flag, curstate, html::FT_SOUT); + // xout + curstate = font.fontInfo().xout(); + if (font_old.xout() != curstate) + doFontSwitch(tagsToOpen, tagsToClose, xout_flag, curstate, html::FT_XOUT); + // double underbar curstate = font.fontInfo().uuline(); if (font_old.uuline() != curstate) @@ -3146,6 +3283,11 @@ bool Paragraph::isHfill(pos_type pos) const bool Paragraph::isNewline(pos_type pos) const { + // U+2028 LINE SEPARATOR + // U+2029 PARAGRAPH SEPARATOR + char_type const c = d->text_[pos]; + if (c == 0x2028 || c == 0x2029) + return true; Inset const * inset = getInset(pos); return inset && inset->lyxCode() == NEWLINE_CODE; } @@ -3327,11 +3469,11 @@ docstring Paragraph::asString(pos_type beg, pos_type end, int options, const Out void Paragraph::forOutliner(docstring & os, size_t const maxlen, - bool const shorten) const + bool const shorten, bool const label) const { size_t tmplen = shorten ? maxlen + 1 : maxlen; - if (!d->params_.labelString().empty()) - os += d->params_.labelString() + ' '; + if (label && !labelString().empty()) + os += labelString() + ' '; for (pos_type i = 0; i < size() && os.length() < tmplen; ++i) { if (isDeleted(i)) continue; @@ -3528,6 +3670,12 @@ void Paragraph::setBuffer(Buffer & b) } +void Paragraph::resetBuffer() +{ + d->insetlist_.resetBuffer(); +} + + Inset * Paragraph::releaseInset(pos_type pos) { Inset * inset = d->insetlist_.release(pos); @@ -3693,11 +3841,11 @@ void Paragraph::deregisterWords() Private::LangWordsMap::const_iterator itl = d->words_.begin(); Private::LangWordsMap::const_iterator ite = d->words_.end(); for (; itl != ite; ++itl) { - WordList * wl = theWordList(itl->first); + WordList & wl = theWordList(itl->first); Private::Words::const_iterator it = (itl->second).begin(); Private::Words::const_iterator et = (itl->second).end(); for (; it != et; ++it) - wl->remove(*it); + wl.remove(*it); } d->words_.clear(); } @@ -3773,11 +3921,11 @@ void Paragraph::registerWords() Private::LangWordsMap::const_iterator itl = d->words_.begin(); Private::LangWordsMap::const_iterator ite = d->words_.end(); for (; itl != ite; ++itl) { - WordList * wl = theWordList(itl->first); + WordList & wl = theWordList(itl->first); Private::Words::const_iterator it = (itl->second).begin(); Private::Words::const_iterator et = (itl->second).end(); for (; it != et; ++it) - wl->insert(*it); + wl.insert(*it); } }