X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2FParagraph.cpp;h=f2d97fe7c97cb9dbc60eac15e39e056391b14ec8;hb=7441172d4d9a26eb4824bb8bee003f457ef34f1c;hp=0251752342fd53cca7654daa66a396aa84511960;hpb=8ae0841826d90b8cdee1922f91fd6ccc5009f5ef;p=lyx.git diff --git a/src/Paragraph.cpp b/src/Paragraph.cpp index 0251752342..f2d97fe7c9 100644 --- a/src/Paragraph.cpp +++ b/src/Paragraph.cpp @@ -84,14 +84,6 @@ using namespace lyx::support; namespace lyx { -namespace { - -/// Inset identifier (above 0x10ffff, for ucs-4) -char_type const META_INSET = 0x200001; - -} // namespace - - ///////////////////////////////////////////////////////////////////// // // SpellResultRange @@ -274,9 +266,9 @@ private: Ranges ranges_; /// the area of the paragraph with pending spell check FontSpan refresh_; - bool needs_refresh_; /// spell state cache version number SpellChecker::ChangeNumber current_change_number_; + bool needs_refresh_; void correctRangesAfterPos(pos_type pos, int offset) @@ -460,7 +452,7 @@ public: { int numskips = 0; while (it != et && it->first < start) { - int skip = it->last - it->first + 1; + long skip = it->last - it->first + 1; start += skip; numskips += skip; ++it; @@ -487,9 +479,6 @@ public: /// FontList fontlist_; - /// - int id_; - /// ParagraphParameters params_; @@ -514,11 +503,13 @@ public: Layout const * layout_; /// SpellCheckerState speller_state_; + /// + int id_; }; Paragraph::Private::Private(Paragraph * owner, Layout const & layout) - : owner_(owner), inset_owner_(nullptr), id_(-1), begin_of_body_(0), layout_(&layout) + : owner_(owner), inset_owner_(nullptr), begin_of_body_(0), layout_(&layout), id_(-1) { text_.reserve(100); } @@ -531,17 +522,16 @@ int Paragraph::Private::make_id() // LFUN_PARAGRAPH_GOTO to switch to a different buffer, for instance in the // outliner. // (thread-safe) - static atomic_uint next_id(0); + static int next_id(0); return next_id++; } Paragraph::Private::Private(Private const & p, Paragraph * owner) : owner_(owner), inset_owner_(p.inset_owner_), fontlist_(p.fontlist_), - id_(make_id()), params_(p.params_), changes_(p.changes_), insetlist_(p.insetlist_), begin_of_body_(p.begin_of_body_), text_(p.text_), words_(p.words_), - layout_(p.layout_) + layout_(p.layout_), id_(make_id()) { requestSpellCheck(p.text_.size()); } @@ -549,11 +539,11 @@ Paragraph::Private::Private(Private const & p, Paragraph * owner) Paragraph::Private::Private(Private const & p, Paragraph * owner, pos_type beg, pos_type end) - : owner_(owner), inset_owner_(p.inset_owner_), id_(make_id()), + : owner_(owner), inset_owner_(p.inset_owner_), params_(p.params_), changes_(p.changes_), insetlist_(p.insetlist_, beg, end), begin_of_body_(p.begin_of_body_), words_(p.words_), - layout_(p.layout_) + layout_(p.layout_), id_(make_id()) { if (beg >= pos_type(p.text_.size())) return; @@ -1053,9 +1043,11 @@ void Paragraph::Private::latexInset(BufferParams const & bparams, bool needPar = false; bool closeLanguage = arabtex || basefont.isRightToLeft() == running_font.isRightToLeft(); + // We pass non_inherit_inset = true here since size switches + // ought not to be terminated here (#8384). unsigned int count = running_font.latexWriteEndChanges(os, bparams, runparams, basefont, basefont, - needPar, closeLanguage); + needPar, closeLanguage, true); column += count; // if any font properties were closed, update the running_font, // making sure, however, to leave the language as it was @@ -1067,8 +1059,15 @@ void Paragraph::Private::latexInset(BufferParams const & bparams, running_font = basefont; if (!closeLanguage) running_font.setLanguage(copy_font.language()); - // leave font open if language is still open - open_font = (running_font.language() == basefont.language()); + // For these, we use switches, so no need to close + basefont.fontInfo().setSize(copy_font.fontInfo().size()); + basefont.fontInfo().setFamily(copy_font.fontInfo().family()); + basefont.fontInfo().setSeries(copy_font.fontInfo().series()); + // leave font open if language or any of the switches is still open + open_font = (running_font.language() == basefont.language() + || running_font.fontInfo().size() == basefont.fontInfo().size() + || running_font.fontInfo().family() == basefont.fontInfo().family() + || running_font.fontInfo().series() == basefont.fontInfo().series()); if (closeLanguage) runparams.local_font = &basefont; } @@ -2394,6 +2393,11 @@ void Paragraph::latex(BufferParams const & bparams, pos_type body_pos = beginOfBody(); unsigned int column = 0; + // If we are inside an non inheritFont() inset, the real outerfont is local_font + Font const real_outerfont = (!inInset().inheritFont() + && runparams.local_font != nullptr) + ? Font(runparams.local_font->fontInfo()) : outerfont; + if (body_pos > 0) { // the optional argument is kept in curly brackets in // case it contains a ']' @@ -2403,9 +2407,9 @@ void Paragraph::latex(BufferParams const & bparams, // braces when it parses \item. os << "[{"; column += 2; - basefont = getLabelFont(bparams, outerfont); + basefont = getLabelFont(bparams, real_outerfont); } else { - basefont = getLayoutFont(bparams, outerfont); + basefont = getLayoutFont(bparams, real_outerfont); } // Which font is currently active? @@ -2450,7 +2454,7 @@ void Paragraph::latex(BufferParams const & bparams, basefont, basefont, needPar); open_font = false; } - basefont = getLayoutFont(bparams, outerfont); + basefont = getLayoutFont(bparams, real_outerfont); running_font = basefont; column += Changes::latexMarkChange(os, bparams, @@ -2517,8 +2521,8 @@ void Paragraph::latex(BufferParams const & bparams, basefont, needPar); open_font = false; } - basefont = (body_pos > i) ? getLabelFont(bparams, outerfont) - : getLayoutFont(bparams, outerfont); + basefont = (body_pos > i) ? getLabelFont(bparams, real_outerfont) + : getLayoutFont(bparams, real_outerfont); running_font = basefont; column += Changes::latexMarkChange(os, bparams, Change(Change::INSERTED), change, rp); @@ -2538,8 +2542,8 @@ void Paragraph::latex(BufferParams const & bparams, basefont, basefont, needPar); open_font = false; } - basefont = (body_pos > i) ? getLabelFont(bparams, outerfont) - : getLayoutFont(bparams, outerfont); + basefont = (body_pos > i) ? getLabelFont(bparams, real_outerfont) + : getLayoutFont(bparams, real_outerfont); running_font = basefont; column += Changes::latexMarkChange(os, bparams, runningChange, change, runparams); @@ -2651,10 +2655,11 @@ void Paragraph::latex(BufferParams const & bparams, os << '}'; column += 1; } - odocstringstream ods; - column += current_font.latexWriteStartChanges(ods, bparams, + otexstringstream ots; + bool const non_inherit_inset = (c == META_INSET && getInset(i) && !getInset(i)->inheritFont()); + column += current_font.latexWriteStartChanges(ots, bparams, runparams, basefont, - last_font); + last_font, non_inherit_inset); // Check again for display math in ulem commands as a // font change may also occur just before a math inset. if (runparams.inDisplayMath && !deleted_display_math @@ -2666,19 +2671,17 @@ void Paragraph::latex(BufferParams const & bparams, } running_font = current_font; open_font = true; - docstring fontchange = ods.str(); + docstring fontchange = ots.str(); + os << fontchange; // check whether the fontchange ends with a \\textcolor - // modifier and the text starts with a space (bug 4473) + // modifier and the text starts with a space. If so we + // need to add } in order to prevent \\textcolor from gobbling + // the space (bug 4473). docstring const last_modifier = rsplit(fontchange, '\\'); if (prefixIs(last_modifier, from_ascii("textcolor")) && c == ' ') - os << fontchange << from_ascii("{}"); - // check if the fontchange ends with a trailing blank - // (like "\small " (see bug 3382) - else if (suffixIs(fontchange, ' ') && c == ' ') - os << fontchange.substr(0, fontchange.size() - 1) - << from_ascii("{}"); - else - os << fontchange; + os << from_ascii("{}"); + else if (ots.terminateCommand()) + os << termcmd; if (in_ct_deletion) { // We have to close and then reopen \lyxdeleted, // as strikeout needs to be on lowest level. @@ -2737,10 +2740,10 @@ void Paragraph::latex(BufferParams const & bparams, pit < 0 || pars[pit].empty() ? pars[pit].getLayoutFont( bparams, - outerfont) + real_outerfont) : pars[pit].getFont(bparams, pars[pit].size() - 1, - outerfont); + real_outerfont); if (lastfont.fontInfo().size() != basefont.fontInfo().size()) { ++parInline; @@ -2748,7 +2751,7 @@ void Paragraph::latex(BufferParams const & bparams, } } d->latexInset(bparams, os, rp, running_font, - basefont, outerfont, open_font, + basefont, real_outerfont, open_font, runningChange, style, i, column); if (incremented) --parInline; @@ -2833,8 +2836,8 @@ void Paragraph::latex(BufferParams const & bparams, // since this produces unwanted whitespace. Font const font = empty() - ? getLayoutFont(bparams, outerfont) - : getFont(bparams, size() - 1, outerfont); + ? getLayoutFont(bparams, real_outerfont) + : getFont(bparams, size() - 1, real_outerfont); InsetText const * textinset = inInset().asInsetText(); @@ -3015,11 +3018,11 @@ void doFontSwitchDocBook(vector & tagsToOpen, class OptionalFontType { public: - bool has_value; xml::FontTypes ft; + bool has_value; - OptionalFontType(): has_value(false), ft(xml::FT_EMPH) {} // A possible value at random for ft. - OptionalFontType(xml::FontTypes ft): has_value(true), ft(ft) {} + OptionalFontType(): ft(xml::FT_EMPH), has_value(false) {} // A possible value at random for ft. + OptionalFontType(xml::FontTypes ft): ft(ft), has_value(true) {} }; OptionalFontType fontShapeToXml(FontShape fs) @@ -3046,13 +3049,10 @@ OptionalFontType fontFamilyToXml(FontFamily fm) switch (fm) { case ROMAN_FAMILY: return {xml::FT_ROMAN}; - break; case SANS_FAMILY: return {xml::FT_SANS}; - break; case TYPEWRITER_FAMILY: return {xml::FT_TYPE}; - break; case INHERIT_FAMILY: return {}; default: @@ -3097,16 +3097,12 @@ OptionalFontType fontSizeToXml(FontSize fs) } } -}// anonymous namespace - - -void Paragraph::simpleDocBookOnePar(Buffer const & buf, - XMLStream & xs, - OutputParams const & runparams, - Font const & outerfont, - bool start_paragraph, bool close_paragraph, - pos_type initial) const +struct DocBookFontState { + FontShape curr_fs = INHERIT_SHAPE; + FontFamily curr_fam = INHERIT_FAMILY; + FontSize curr_size = INHERIT_SIZE; + // track whether we have opened these tags bool emph_flag = false; bool bold_flag = false; @@ -3114,6 +3110,7 @@ void Paragraph::simpleDocBookOnePar(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; @@ -3121,117 +3118,102 @@ void Paragraph::simpleDocBookOnePar(Buffer const & buf, bool faml_flag = false; // size tags bool size_flag = false; +}; - Layout const & style = *d->layout_; - - if (start_paragraph) - xs.startDivision(allowEmpty()); - - FontInfo font_old = - style.labeltype == LABEL_MANUAL ? style.labelfont : style.font; - - FontShape curr_fs = INHERIT_SHAPE; - FontFamily curr_fam = INHERIT_FAMILY; - FontSize curr_size = INHERIT_SIZE; - - string const default_family = - buf.masterBuffer()->params().fonts_default_family; - +std::tuple, vector> computeDocBookFontSwitch(FontInfo const & font_old, + Font const & font, + std::string const & default_family, + DocBookFontState & fs) +{ vector tagsToOpen; vector tagsToClose; - // parsing main loop - for (pos_type i = initial; i < size(); ++i) { - // let's not show deleted material in the output - if (isDeleted(i)) - continue; - - Font const font = getFont(buf.masterBuffer()->params(), i, outerfont); - - // emphasis - FontState curstate = font.fontInfo().emph(); - if (font_old.emph() != curstate) - doFontSwitchDocBook(tagsToOpen, tagsToClose, emph_flag, curstate, xml::FT_EMPH); - - // noun - curstate = font.fontInfo().noun(); - if (font_old.noun() != curstate) - doFontSwitchDocBook(tagsToOpen, tagsToClose, noun_flag, curstate, xml::FT_NOUN); - - // underbar - curstate = font.fontInfo().underbar(); - if (font_old.underbar() != curstate) - doFontSwitchDocBook(tagsToOpen, tagsToClose, ubar_flag, curstate, xml::FT_UBAR); - - // strikeout - curstate = font.fontInfo().strikeout(); - if (font_old.strikeout() != curstate) - doFontSwitchDocBook(tagsToOpen, tagsToClose, sout_flag, curstate, xml::FT_SOUT); - - // double underbar - curstate = font.fontInfo().uuline(); - if (font_old.uuline() != curstate) - doFontSwitchDocBook(tagsToOpen, tagsToClose, dbar_flag, curstate, xml::FT_DBAR); - - // wavy line - curstate = font.fontInfo().uwave(); - if (font_old.uwave() != curstate) - doFontSwitchDocBook(tagsToOpen, tagsToClose, wave_flag, curstate, xml::FT_WAVE); - - // bold - // a little hackish, but allows us to reuse what we have. - curstate = (font.fontInfo().series() == BOLD_SERIES ? FONT_ON : FONT_OFF); - if (font_old.series() != font.fontInfo().series()) - doFontSwitchDocBook(tagsToOpen, tagsToClose, bold_flag, curstate, xml::FT_BOLD); + // emphasis + FontState curstate = font.fontInfo().emph(); + if (font_old.emph() != curstate) + doFontSwitchDocBook(tagsToOpen, tagsToClose, fs.emph_flag, curstate, xml::FT_EMPH); + + // noun + curstate = font.fontInfo().noun(); + if (font_old.noun() != curstate) + doFontSwitchDocBook(tagsToOpen, tagsToClose, fs.noun_flag, curstate, xml::FT_NOUN); + + // underbar + curstate = font.fontInfo().underbar(); + if (font_old.underbar() != curstate) + doFontSwitchDocBook(tagsToOpen, tagsToClose, fs.ubar_flag, curstate, xml::FT_UBAR); + + // strikeout + curstate = font.fontInfo().strikeout(); + if (font_old.strikeout() != curstate) + doFontSwitchDocBook(tagsToOpen, tagsToClose, fs.sout_flag, curstate, xml::FT_SOUT); + + // xout + curstate = font.fontInfo().xout(); + if (font_old.xout() != curstate) + doFontSwitchDocBook(tagsToOpen, tagsToClose, fs.xout_flag, curstate, xml::FT_XOUT); + + // double underbar + curstate = font.fontInfo().uuline(); + if (font_old.uuline() != curstate) + doFontSwitchDocBook(tagsToOpen, tagsToClose, fs.dbar_flag, curstate, xml::FT_DBAR); + + // wavy line + curstate = font.fontInfo().uwave(); + if (font_old.uwave() != curstate) + doFontSwitchDocBook(tagsToOpen, tagsToClose, fs.wave_flag, curstate, xml::FT_WAVE); + + // bold + // a little hackish, but allows us to reuse what we have. + curstate = (font.fontInfo().series() == BOLD_SERIES ? FONT_ON : FONT_OFF); + if (font_old.series() != font.fontInfo().series()) + doFontSwitchDocBook(tagsToOpen, tagsToClose, fs.bold_flag, curstate, xml::FT_BOLD); + + // Font shape + fs.curr_fs = font.fontInfo().shape(); + FontShape old_fs = font_old.shape(); + if (old_fs != fs.curr_fs) { + if (fs.shap_flag) { + OptionalFontType tag = fontShapeToXml(old_fs); + if (tag.has_value) + tagsToClose.push_back(docbookEndFontTag(tag.ft)); + fs.shap_flag = false; + } - // Font shape - curr_fs = font.fontInfo().shape(); - FontShape old_fs = font_old.shape(); - if (old_fs != curr_fs) { - if (shap_flag) { - OptionalFontType tag = fontShapeToXml(old_fs); - if (tag.has_value) { - tagsToClose.push_back(docbookEndFontTag(tag.ft)); - } - shap_flag = false; - } + OptionalFontType tag = fontShapeToXml(fs.curr_fs); + if (tag.has_value) + tagsToOpen.push_back(docbookStartFontTag(tag.ft)); + } - OptionalFontType tag = fontShapeToXml(curr_fs); - if (tag.has_value) { - tagsToOpen.push_back(docbookStartFontTag(tag.ft)); - } + // Font family + fs.curr_fam = font.fontInfo().family(); + FontFamily old_fam = font_old.family(); + if (old_fam != fs.curr_fam) { + if (fs.faml_flag) { + OptionalFontType tag = fontFamilyToXml(old_fam); + if (tag.has_value) + tagsToClose.push_back(docbookEndFontTag(tag.ft)); + fs.faml_flag = false; } - - // Font family - curr_fam = font.fontInfo().family(); - 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) { + switch (fs.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; + fs.faml_flag = true; } break; case SANS_FAMILY: if (default_family != "sfdefault") { tagsToOpen.push_back(docbookStartFontTag(xml::FT_SANS)); - faml_flag = true; + fs.faml_flag = true; } break; case TYPEWRITER_FAMILY: if (default_family != "ttdefault") { tagsToOpen.push_back(docbookStartFontTag(xml::FT_TYPE)); - faml_flag = true; + fs.faml_flag = true; } break; case INHERIT_FAMILY: @@ -3240,27 +3222,66 @@ void Paragraph::simpleDocBookOnePar(Buffer const & buf, // the other tags are for internal use LATTEST(false); break; - } } + } - // 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; - } + // Font size + fs.curr_size = font.fontInfo().size(); + FontSize old_size = font_old.size(); + if (old_size != fs.curr_size) { + if (fs.size_flag) { + OptionalFontType tag = fontSizeToXml(old_size); + if (tag.has_value) + tagsToClose.push_back(docbookEndFontTag(tag.ft)); + fs.size_flag = false; + } - OptionalFontType tag = fontSizeToXml(curr_size); - if (tag.has_value) { - tagsToOpen.push_back(docbookStartFontTag(tag.ft)); - size_flag = true; - } + OptionalFontType tag = fontSizeToXml(fs.curr_size); + if (tag.has_value) { + tagsToOpen.push_back(docbookStartFontTag(tag.ft)); + fs.size_flag = true; } + } + + return std::tuple, vector>(tagsToOpen, tagsToClose); +} + +} // anonymous namespace + + +void Paragraph::simpleDocBookOnePar(Buffer const & buf, + XMLStream & xs, + OutputParams const & runparams, + Font const & outerfont, + bool start_paragraph, bool close_paragraph, + pos_type initial) const +{ + // track whether we have opened these tags + DocBookFontState fs; + + if (start_paragraph) + xs.startDivision(allowEmpty()); + + Layout const & style = *d->layout_; + FontInfo font_old = + style.labeltype == LABEL_MANUAL ? style.labelfont : style.font; + + string const default_family = + buf.masterBuffer()->params().fonts_default_family; + + vector tagsToOpen; + vector tagsToClose; + + // parsing main loop + for (pos_type i = initial; i < size(); ++i) { + // let's not show deleted material in the output + if (isDeleted(i)) + continue; + + Font const font = getFont(buf.masterBuffer()->params(), i, outerfont); + + // Determine which tags should be opened or closed. + tie(tagsToOpen, tagsToClose) = computeDocBookFontSwitch(font_old, font, default_family, fs); // FIXME XHTML // Other such tags? What about the other text ranges? @@ -3284,6 +3305,8 @@ void Paragraph::simpleDocBookOnePar(Buffer const & buf, np.local_font = &font; // If the paragraph has size 1, then we are in the "special // 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! np.docbook_in_par = true; inset->docbook(xs, np);