X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2FParagraph.cpp;h=7fd271c41d619eaf42c6c23d460b5d18e2ad7650;hb=26910d5ec49395d1372dd5b9259f1bf6ed23de0a;hp=5cfce9bec536679dfa09775526a317805aec291b;hpb=97d48fbd6a3c3183a4b9a7bd58c9ac2001506163;p=lyx.git diff --git a/src/Paragraph.cpp b/src/Paragraph.cpp index 5cfce9bec5..7fd271c41d 100644 --- a/src/Paragraph.cpp +++ b/src/Paragraph.cpp @@ -69,8 +69,10 @@ using namespace lyx::support; namespace lyx { namespace { + /// Inset identifier (above 0x10ffff, for ucs-4) char_type const META_INSET = 0x200001; + } @@ -129,12 +131,13 @@ private: class SpellCheckerState { public: - SpellCheckerState() { + SpellCheckerState() + { needs_refresh_ = true; current_change_number_ = 0; } - void setRange(FontSpan const fp, SpellChecker::Result state) + void setRange(FontSpan const & fp, SpellChecker::Result state) { Ranges result; RangesIterator et = ranges_.end(); @@ -209,20 +212,24 @@ public: return empty_; } - bool needsRefresh() const { + bool needsRefresh() const + { return needs_refresh_; } - SpellChecker::ChangeNumber currentChangeNumber() const { + SpellChecker::ChangeNumber currentChangeNumber() const + { return current_change_number_; } - void refreshRange(pos_type & first, pos_type & last) const { + void refreshRange(pos_type & first, pos_type & last) const + { first = refresh_.first; last = refresh_.last; } - void needsRefresh(pos_type pos) { + void needsRefresh(pos_type pos) + { if (needs_refresh_ && pos != -1) { if (pos < refresh_.first) refresh_.first = pos; @@ -237,13 +244,13 @@ public: needs_refresh_ = pos != -1; } - void needsCompleteRefresh(SpellChecker::ChangeNumber change_number) { + void needsCompleteRefresh(SpellChecker::ChangeNumber change_number) + { needs_refresh_ = true; refresh_.first = 0; refresh_.last = -1; current_change_number_ = change_number; } - private: typedef vector Ranges; typedef Ranges::const_iterator RangesIterator; @@ -330,6 +337,7 @@ public: /// void latexSpecialChar( otexstream & os, + BufferParams const & bparams, OutputParams const & runparams, Font const & running_font, Change const & running_change, @@ -345,6 +353,12 @@ public: pos_type i, unsigned int & column); /// + bool latexSpecialT3( + char_type const c, + otexstream & os, + pos_type i, + unsigned int & column); + /// bool latexSpecialTypewriter( char_type const c, otexstream & os, @@ -377,9 +391,10 @@ public: Language * getSpellLanguage(pos_type const from) const; Language * locateSpellRange(pos_type & from, pos_type & to, - SkipPositions & skips) const; + SkipPositions & skips) const; - bool hasSpellerChange() const { + bool hasSpellerChange() const + { SpellChecker::ChangeNumber speller_change_number = 0; if (theSpellChecker()) speller_change_number = theSpellChecker()->changeNumber(); @@ -398,14 +413,16 @@ public: speller_state_.setRange(fp, state); } - void requestSpellCheck(pos_type pos) { + void requestSpellCheck(pos_type pos) + { if (pos == -1) speller_state_.needsCompleteRefresh(speller_state_.currentChangeNumber()); else speller_state_.needsRefresh(pos); } - void readySpellCheck() { + void readySpellCheck() + { speller_state_.needsRefresh(-1); } @@ -568,16 +585,16 @@ Paragraph::Private::Private(Private const & p, Paragraph * owner, void Paragraph::addChangesToToc(DocIterator const & cdit, - Buffer const & buf) const + Buffer const & buf, bool output_active) const { - d->changes_.addToToc(cdit, buf); + d->changes_.addToToc(cdit, buf, output_active); } bool Paragraph::isDeleted(pos_type start, pos_type end) const { - LASSERT(start >= 0 && start <= size(), /**/); - LASSERT(end > start && end <= size() + 1, /**/); + LASSERT(start >= 0 && start <= size(), return false); + LASSERT(end > start && end <= size() + 1, return false); return d->changes_.isDeleted(start, end); } @@ -585,8 +602,8 @@ bool Paragraph::isDeleted(pos_type start, pos_type end) const bool Paragraph::isChanged(pos_type start, pos_type end) const { - LASSERT(start >= 0 && start <= size(), /**/); - LASSERT(end > start && end <= size() + 1, /**/); + LASSERT(start >= 0 && start <= size(), return false); + LASSERT(end > start && end <= size() + 1, return false); return d->changes_.isChanged(start, end); } @@ -631,7 +648,7 @@ void Paragraph::setChange(Change const & change) void Paragraph::setChange(pos_type pos, Change const & change) { - LASSERT(pos >= 0 && pos <= size(), /**/); + LASSERT(pos >= 0 && pos <= size(), return); d->changes_.set(change, pos); // see comment in setChange(Change const &) above @@ -643,15 +660,15 @@ void Paragraph::setChange(pos_type pos, Change const & change) Change const & Paragraph::lookupChange(pos_type pos) const { - LASSERT(pos >= 0 && pos <= size(), /**/); + LBUFERR(pos >= 0 && pos <= size()); return d->changes_.lookup(pos); } void Paragraph::acceptChanges(pos_type start, pos_type end) { - LASSERT(start >= 0 && start <= size(), /**/); - LASSERT(end > start && end <= size() + 1, /**/); + LASSERT(start >= 0 && start <= size(), return); + LASSERT(end > start && end <= size() + 1, return); for (pos_type pos = start; pos < end; ++pos) { switch (lookupChange(pos).type) { @@ -685,8 +702,8 @@ void Paragraph::acceptChanges(pos_type start, pos_type end) void Paragraph::rejectChanges(pos_type start, pos_type end) { - LASSERT(start >= 0 && start <= size(), /**/); - LASSERT(end > start && end <= size() + 1, /**/); + LASSERT(start >= 0 && start <= size(), return); + LASSERT(end > start && end <= size() + 1, return); for (pos_type pos = start; pos < end; ++pos) { switch (lookupChange(pos).type) { @@ -721,7 +738,7 @@ void Paragraph::rejectChanges(pos_type start, pos_type end) void Paragraph::Private::insertChar(pos_type pos, char_type c, Change const & change) { - LASSERT(pos >= 0 && pos <= int(text_.size()), /**/); + LASSERT(pos >= 0 && pos <= int(text_.size()), return); // track change changes_.insert(change, pos); @@ -750,10 +767,10 @@ void Paragraph::Private::insertChar(pos_type pos, char_type c, bool Paragraph::insertInset(pos_type pos, Inset * inset, - Change const & change) + Font const & font, Change const & change) { - LASSERT(inset, /**/); - LASSERT(pos >= 0 && pos <= size(), /**/); + LASSERT(inset, return false); + LASSERT(pos >= 0 && pos <= size(), return false); // Paragraph::insertInset() can be used in cut/copy/paste operation where // d->inset_owner_ is not set yet. @@ -761,13 +778,14 @@ bool Paragraph::insertInset(pos_type pos, Inset * inset, return false; d->insertChar(pos, META_INSET, change); - LASSERT(d->text_[pos] == META_INSET, /**/); + LASSERT(d->text_[pos] == META_INSET, return false); // Add a new entry in the insetlist_. d->insetlist_.insert(inset, pos); // Some insets require run of spell checker requestSpellCheck(pos); + setFont(pos, font); return true; } @@ -829,8 +847,8 @@ bool Paragraph::eraseChar(pos_type pos, bool trackChanges) int Paragraph::eraseChars(pos_type start, pos_type end, bool trackChanges) { - LASSERT(start >= 0 && start <= size(), /**/); - LASSERT(end >= start && end <= size() + 1, /**/); + LASSERT(start >= 0 && start <= size(), return 0); + LASSERT(end >= start && end <= size() + 1, return 0); pos_type i = start; for (pos_type count = end - start; count; --count) { @@ -852,8 +870,14 @@ int Paragraph::Private::latexSurrogatePair(otexstream & os, char_type c, // FIXME: change tracking // Is this correct WRT change tracking? Encoding const & encoding = *(runparams.encoding); - docstring const latex1 = encoding.latexChar(next); - docstring const latex2 = encoding.latexChar(c); + docstring latex1 = encoding.latexChar(next).first; + if (runparams.inIPA) { + string const tipashortcut = Encodings::TIPAShortcut(next); + if (!tipashortcut.empty()) { + latex1 = from_ascii(tipashortcut); + } + } + docstring const latex2 = encoding.latexChar(c).first; if (docstring(1, next) == latex1) { // the encoding supports the combination os << latex2 << latex1; @@ -969,7 +993,7 @@ int Paragraph::Private::writeScriptChars(otexstream & os, // Stop here if there is a font attribute or encoding change. if (found && cit != end && prev_font != cit->font()) break; - docstring const latex = encoding.latexChar(next); + docstring const latex = encoding.latexChar(next).first; docstring::size_type const b1 = latex.find_first_of(from_ascii("{")); docstring::size_type const b2 = @@ -1020,10 +1044,12 @@ void Paragraph::Private::latexInset(BufferParams const & bparams, unsigned int & column) { Inset * inset = owner_->getInset(i); - LASSERT(inset, /**/); + LBUFERR(inset); if (style.pass_thru) { - inset->plaintext(os.os(), runparams); + odocstringstream ods; + inset->plaintext(ods, runparams); + os << ods.str(); return; } @@ -1070,6 +1096,7 @@ void Paragraph::Private::latexInset(BufferParams const & bparams, odocstream::pos_type const len = os.os().tellp(); if (inset->forceLTR() + && !runparams.use_polyglossia && running_font.isRightToLeft() // ERT is an exception, it should be output with no // decorations at all @@ -1149,6 +1176,7 @@ void Paragraph::Private::latexInset(BufferParams const & bparams, void Paragraph::Private::latexSpecialChar(otexstream & os, + BufferParams const & bparams, OutputParams const & runparams, Font const & running_font, Change const & running_change, @@ -1157,29 +1185,36 @@ void Paragraph::Private::latexSpecialChar(otexstream & os, pos_type end_pos, unsigned int & column) { - char_type const c = text_[i]; + // With polyglossia, brackets and stuff need not be reversed + // in RTL scripts (see bug #8251) + char_type const c = (runparams.use_polyglossia) ? + owner_->getUChar(bparams, i) : text_[i]; if (style.pass_thru || runparams.pass_thru) { if (c != '\0') { Encoding const * const enc = runparams.encoding; - if (enc && enc->latexChar(c, true).empty()) + if (enc && !enc->encodable(c)) throw EncodingException(c); os.put(c); } return; } + // TIPA uses its own T3 encoding + if (runparams.inIPA && latexSpecialT3(c, os, i, column)) + return; // If T1 font encoding is used, use the special // characters it provides. // NOTE: some languages reset the font encoding // internally - if (!running_font.language()->internalFontEncoding() + if (!runparams.inIPA && !running_font.language()->internalFontEncoding() && lyxrc.fontenc == "T1" && latexSpecialT1(c, os, i, column)) return; // \tt font needs special treatment - if (running_font.fontInfo().family() == TYPEWRITER_FAMILY - && latexSpecialTypewriter(c, os, i, column)) + if (!runparams.inIPA + && running_font.fontInfo().family() == TYPEWRITER_FAMILY + && latexSpecialTypewriter(c, os, i, column)) return; // Otherwise, we use what LaTeX provides us. @@ -1253,8 +1288,9 @@ void Paragraph::Private::latexSpecialChar(otexstream & os, return; Encoding const & encoding = *(runparams.encoding); + char_type next = '\0'; if (i + 1 < int(text_.size())) { - char_type next = text_[i + 1]; + next = text_[i + 1]; if (Encodings::isCombiningChar(next)) { column += latexSurrogatePair(os, c, next, runparams) - 1; ++i; @@ -1262,20 +1298,50 @@ void Paragraph::Private::latexSpecialChar(otexstream & os, } } string script; - docstring const latex = encoding.latexChar(c); + pair latex = encoding.latexChar(c); + docstring nextlatex; + bool nexttipas = false; + string nexttipashortcut; + if (next != '\0' && next != META_INSET) { + nextlatex = encoding.latexChar(next).first; + if (runparams.inIPA) { + nexttipashortcut = Encodings::TIPAShortcut(next); + nexttipas = !nexttipashortcut.empty(); + } + } + bool tipas = false; + if (runparams.inIPA) { + string const tipashortcut = Encodings::TIPAShortcut(c); + if (!tipashortcut.empty()) { + latex.first = from_ascii(tipashortcut); + latex.second = false; + tipas = true; + } + } if (Encodings::isKnownScriptChar(c, script) - && prefixIs(latex, from_ascii("\\" + script))) - column += writeScriptChars(os, latex, + && prefixIs(latex.first, from_ascii("\\" + script))) + column += writeScriptChars(os, latex.first, running_change, encoding, i) - 1; - else if (latex.length() > 1 && latex[latex.length() - 1] != '}') { + else if (latex.second + && ((!prefixIs(nextlatex, '\\') + && !prefixIs(nextlatex, '{') + && !prefixIs(nextlatex, '}')) + || (nexttipas + && !prefixIs(from_ascii(nexttipashortcut), '\\'))) + && !tipas) { // Prevent eating of a following // space or command corruption by // following characters - column += latex.length() + 1; - os << latex << "{}"; + if (next == ' ' || next == '\0') { + column += latex.first.length() + 1; + os << latex.first << "{}"; + } else { + column += latex.first.length(); + os << latex.first << " "; + } } else { - column += latex.length() - 1; - os << latex; + column += latex.first.length() - 1; + os << latex.first; } break; } @@ -1310,6 +1376,26 @@ bool Paragraph::Private::latexSpecialT1(char_type const c, otexstream & os, } +bool Paragraph::Private::latexSpecialT3(char_type const c, otexstream & os, + pos_type /*i*/, unsigned int & column) +{ + switch (c) { + case '*': + case '[': + case ']': + case '\"': + os.put(c); + return true; + case '|': + os << "\\textvertline{}"; + column += 14; + return true; + default: + return false; + } +} + + bool Paragraph::Private::latexSpecialTypewriter(char_type const c, otexstream & os, pos_type i, unsigned int & column) { @@ -1378,18 +1464,25 @@ void Paragraph::Private::validate(LaTeXFeatures & features) const // we have to provide all the optional arguments here, even though // the last one is the only one we care about. // Separate handling of optional argument inset. - if (layout_->optargs != 0 || layout_->reqargs != 0) - latexArgInsets(*owner_, os, features.runparams(), - layout_->reqargs, layout_->optargs); - else - os << from_ascii(layout_->latexparam()); + if (!layout_->latexargs().empty()) { + OutputParams rp = features.runparams(); + rp.local_font = &owner_->getFirstFontSettings(bp); + latexArgInsets(*owner_, os, rp, layout_->latexargs()); + } + os << from_ascii(layout_->latexparam()); } docstring::size_type const length = ods.str().length(); // this will output "{" at the beginning, but not at the end owner_->latex(bp, f, os, features.runparams(), 0, -1, true); if (ods.str().length() > length) { - if (is_command) + if (is_command) { ods << '}'; + if (!layout_->postcommandargs().empty()) { + OutputParams rp = features.runparams(); + rp.local_font = &owner_->getFirstFontSettings(bp); + latexArgInsets(*owner_, os, rp, layout_->postcommandargs(), "post:"); + } + } string const snippet = to_utf8(ods.str()); features.addPreambleSnippet(snippet); } @@ -1397,7 +1490,7 @@ void Paragraph::Private::validate(LaTeXFeatures & features) const if (features.runparams().flavor == OutputParams::HTML && layout_->htmltitle()) { - features.setHTMLTitle(owner_->asString(AS_STR_INSETS)); + features.setHTMLTitle(owner_->asString(AS_STR_INSETS | AS_STR_SKIPDELETE)); } // check the params. @@ -1690,16 +1783,6 @@ void Paragraph::insertChar(pos_type pos, char_type c, } -bool Paragraph::insertInset(pos_type pos, Inset * inset, - Font const & font, Change const & change) -{ - bool const success = insertInset(pos, inset, change); - // Set the font/language of the inset... - setFont(pos, font); - return success; -} - - void Paragraph::resetFonts(Font const & font) { d->fontlist_.clear(); @@ -1713,7 +1796,7 @@ Font const & Paragraph::getFontSettings(BufferParams const & bparams, { if (pos > size()) { LYXERR0("pos: " << pos << " size: " << size()); - LASSERT(pos <= size(), /**/); + LBUFERR(false); } FontList::const_iterator cit = d->fontlist_.fontIterator(pos); @@ -1738,9 +1821,9 @@ Font const & Paragraph::getFontSettings(BufferParams const & bparams, FontSpan Paragraph::fontSpan(pos_type pos) const { - LASSERT(pos <= size(), /**/); - pos_type start = 0; + LBUFERR(pos < size()); + pos_type start = 0; FontList::const_iterator cit = d->fontlist_.begin(); FontList::const_iterator end = d->fontlist_.end(); for (; cit != end; ++cit) { @@ -1757,8 +1840,8 @@ FontSpan Paragraph::fontSpan(pos_type pos) const } // This should not happen, but if so, we take no chances. - // LYXERR0("Paragraph::getEndPosOfFontSpan: This should not happen!"); - return FontSpan(pos, pos); + LYXERR0("Paragraph::fontSpan: position not found in fontinfo table!"); + LASSERT(false, return FontSpan(pos, pos)); } @@ -1789,7 +1872,7 @@ Font const & Paragraph::getFirstFontSettings(BufferParams const & bparams) const Font const Paragraph::getFont(BufferParams const & bparams, pos_type pos, Font const & outerfont) const { - LASSERT(pos >= 0, /**/); + LBUFERR(pos >= 0); Font font = getFontSettings(bparams, pos); @@ -1838,16 +1921,23 @@ FontSize Paragraph::highestFontInRange char_type Paragraph::getUChar(BufferParams const & bparams, pos_type pos) const { char_type c = d->text_[pos]; - if (!lyxrc.rtl_support) + if (!lyxrc.rtl_support || !getFontSettings(bparams, pos).isRightToLeft()) return c; + // FIXME: The arabic special casing is due to the difference of arabic + // round brackets input introduced in r18599. Check if this should be + // unified with Hebrew or at least if all bracket types should be + // handled the same (file format change in either case). + string const & lang = getFontSettings(bparams, pos).language()->lang(); + bool const arabic = lang == "arabic_arabtex" || lang == "arabic_arabi" + || lang == "farsi"; char_type uc = c; switch (c) { case '(': - uc = ')'; + uc = arabic ? c : ')'; break; case ')': - uc = '('; + uc = arabic ? c : '('; break; case '[': uc = ']'; @@ -1868,15 +1958,14 @@ char_type Paragraph::getUChar(BufferParams const & bparams, pos_type pos) const uc = '<'; break; } - if (uc != c && getFontSettings(bparams, pos).isRightToLeft()) - return uc; - return c; + + return uc; } void Paragraph::setFont(pos_type pos, Font const & font) { - LASSERT(pos <= size(), /**/); + LASSERT(pos <= size(), return); // First, reduce font against layout/label font // Update: The setCharFont() routine in text2.cpp already @@ -1988,8 +2077,7 @@ docstring Paragraph::expandParagraphLabel(Layout const & layout, bool const in_appendix = process_appendix && d->params_.appendix(); docstring fmt = translateIfPossible(layout.labelstring(in_appendix), lang); - if (fmt.empty() && layout.labeltype == LABEL_COUNTER - && !layout.counter.empty()) + if (fmt.empty() && !layout.counter.empty()) return tclass.counters().theCounter(layout.counter, lang); // handle 'inherited level parts' in 'fmt', @@ -2080,7 +2168,7 @@ bool Paragraph::usePlainLayout() const bool Paragraph::isPassThru() const { - return inInset().getLayout().isPassThru() || d->layout_->pass_thru; + return inInset().isPassThru() || d->layout_->pass_thru; } namespace { @@ -2339,6 +2427,10 @@ void Paragraph::latex(BufferParams const & bparams, os << '{'; ++column; } + if (!style.leftdelim().empty()) { + os << style.leftdelim(); + column += style.leftdelim().size(); + } if (allowcust) column += d->startTeXParParams(bparams, os, runparams); } @@ -2369,6 +2461,11 @@ void Paragraph::latex(BufferParams const & bparams, ++column; } + if (!style.leftdelim().empty()) { + os << style.leftdelim(); + column += style.leftdelim().size(); + } + if (allowcust) column += d->startTeXParParams(bparams, os, runparams); @@ -2508,7 +2605,7 @@ void Paragraph::latex(BufferParams const & bparams, } else { if (i >= start_pos && (end_pos == -1 || i < end_pos)) { try { - d->latexSpecialChar(os, rp, running_font, runningChange, + d->latexSpecialChar(os, bparams, rp, running_font, runningChange, style, i, end_pos, column); } catch (EncodingException & e) { if (runparams.dryrun) { @@ -2559,6 +2656,11 @@ void Paragraph::latex(BufferParams const & bparams, os << "}]~"; } + if (!style.rightdelim().empty()) { + os << style.rightdelim(); + column += style.rightdelim().size(); + } + if (allowcust && d->endTeXParParams(bparams, os, runparams) && runparams.encoding != prev_encoding) { runparams.encoding = prev_encoding; @@ -2720,6 +2822,22 @@ void Paragraph::simpleDocBookOnePar(Buffer const & buf, } +namespace { +void doFontSwitch(vector & tagsToOpen, + vector & tagsToClose, + bool & flag, FontState curstate, html::FontTypes type) +{ + if (curstate == FONT_ON) { + tagsToOpen.push_back(html::FontTag(type)); + flag = true; + } else if (flag) { + tagsToClose.push_back(html::EndFontTag(type)); + flag = false; + } +} +} + + docstring Paragraph::simpleLyXHTMLOnePar(Buffer const & buf, XHTMLStream & xs, OutputParams const & runparams, @@ -2728,65 +2846,317 @@ docstring Paragraph::simpleLyXHTMLOnePar(Buffer const & buf, { docstring retval; + // track whether we have opened these tags bool emph_flag = false; bool bold_flag = false; + bool noun_flag = false; + bool ubar_flag = false; + bool dbar_flag = false; + bool sout_flag = false; + bool wave_flag = false; + // shape tags + bool shap_flag = false; + // family tags + bool faml_flag = false; + // size tags + bool size_flag = false; Layout const & style = *d->layout_; xs.startParagraph(allowEmpty()); - if (!runparams.for_toc && runparams.html_make_pars) { - // generate a magic label for this paragraph - string const attr = "id='" + magicLabel() + "'"; - xs << html::CompTag("a", attr); - } - FontInfo font_old = style.labeltype == LABEL_MANUAL ? style.labelfont : style.font; + FontShape curr_fs = INHERIT_SHAPE; + FontFamily curr_fam = INHERIT_FAMILY; + FontSize curr_size = FONT_SIZE_INHERIT; + + 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 font = getFont(buf.params(), i, outerfont); + Font const font = getFont(buf.masterBuffer()->params(), i, outerfont); // emphasis - if (font_old.emph() != font.fontInfo().emph()) { - if (font.fontInfo().emph() == FONT_ON) { - xs << html::StartTag("em"); - emph_flag = true; - } else if (emph_flag && i != initial) { - xs << html::EndTag("em"); - emph_flag = false; + FontState curstate = font.fontInfo().emph(); + if (font_old.emph() != curstate) + doFontSwitch(tagsToOpen, tagsToClose, emph_flag, curstate, html::FT_EMPH); + + // noun + curstate = font.fontInfo().noun(); + if (font_old.noun() != curstate) + doFontSwitch(tagsToOpen, tagsToClose, noun_flag, curstate, html::FT_NOUN); + + // underbar + curstate = font.fontInfo().underbar(); + if (font_old.underbar() != curstate) + doFontSwitch(tagsToOpen, tagsToClose, ubar_flag, curstate, html::FT_UBAR); + + // strikeout + curstate = font.fontInfo().strikeout(); + if (font_old.strikeout() != curstate) + doFontSwitch(tagsToOpen, tagsToClose, sout_flag, curstate, html::FT_SOUT); + + // double underbar + curstate = font.fontInfo().uuline(); + if (font_old.uuline() != curstate) + doFontSwitch(tagsToOpen, tagsToClose, dbar_flag, curstate, html::FT_DBAR); + + // wavy line + curstate = font.fontInfo().uwave(); + if (font_old.uwave() != curstate) + doFontSwitch(tagsToOpen, tagsToClose, wave_flag, curstate, html::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()) + doFontSwitch(tagsToOpen, tagsToClose, bold_flag, curstate, html::FT_BOLD); + + // Font shape + curr_fs = font.fontInfo().shape(); + FontShape old_fs = font_old.shape(); + if (old_fs != curr_fs) { + if (shap_flag) { + switch (old_fs) { + case ITALIC_SHAPE: + tagsToClose.push_back(html::EndFontTag(html::FT_ITALIC)); + break; + case SLANTED_SHAPE: + tagsToClose.push_back(html::EndFontTag(html::FT_SLANTED)); + break; + case SMALLCAPS_SHAPE: + tagsToClose.push_back(html::EndFontTag(html::FT_SMALLCAPS)); + break; + case UP_SHAPE: + case INHERIT_SHAPE: + break; + default: + // the other tags are for internal use + LATTEST(false); + break; + } + shap_flag = false; + } + switch (curr_fs) { + case ITALIC_SHAPE: + tagsToOpen.push_back(html::FontTag(html::FT_ITALIC)); + shap_flag = true; + break; + case SLANTED_SHAPE: + tagsToOpen.push_back(html::FontTag(html::FT_SLANTED)); + shap_flag = true; + break; + case SMALLCAPS_SHAPE: + tagsToOpen.push_back(html::FontTag(html::FT_SMALLCAPS)); + shap_flag = true; + break; + case UP_SHAPE: + case INHERIT_SHAPE: + break; + default: + // the other tags are for internal use + LATTEST(false); + break; } } - // bold - if (font_old.series() != font.fontInfo().series()) { - if (font.fontInfo().series() == BOLD_SERIES) { - xs << html::StartTag("strong"); - bold_flag = true; - } else if (bold_flag && i != initial) { - xs << html::EndTag("strong"); - bold_flag = false; + + // Font family + curr_fam = font.fontInfo().family(); + FontFamily old_fam = font_old.family(); + if (old_fam != curr_fam) { + if (faml_flag) { + switch (old_fam) { + case ROMAN_FAMILY: + tagsToClose.push_back(html::EndFontTag(html::FT_ROMAN)); + break; + case SANS_FAMILY: + tagsToClose.push_back(html::EndFontTag(html::FT_SANS)); + break; + case TYPEWRITER_FAMILY: + tagsToClose.push_back(html::EndFontTag(html::FT_TYPE)); + break; + case INHERIT_FAMILY: + break; + default: + // the other tags are for internal use + LATTEST(false); + break; + } + 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(html::FontTag(html::FT_ROMAN)); + faml_flag = true; + } + break; + case SANS_FAMILY: + if (default_family != "sfdefault") { + tagsToOpen.push_back(html::FontTag(html::FT_SANS)); + faml_flag = true; + } + break; + case TYPEWRITER_FAMILY: + if (default_family != "ttdefault") { + tagsToOpen.push_back(html::FontTag(html::FT_TYPE)); + faml_flag = true; + } + break; + case INHERIT_FAMILY: + break; + default: + // 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) { + switch (old_size) { + case FONT_SIZE_TINY: + tagsToClose.push_back(html::EndFontTag(html::FT_SIZE_TINY)); + break; + case FONT_SIZE_SCRIPT: + tagsToClose.push_back(html::EndFontTag(html::FT_SIZE_SCRIPT)); + break; + case FONT_SIZE_FOOTNOTE: + tagsToClose.push_back(html::EndFontTag(html::FT_SIZE_FOOTNOTE)); + break; + case FONT_SIZE_SMALL: + tagsToClose.push_back(html::EndFontTag(html::FT_SIZE_SMALL)); + break; + case FONT_SIZE_LARGE: + tagsToClose.push_back(html::EndFontTag(html::FT_SIZE_LARGE)); + break; + case FONT_SIZE_LARGER: + tagsToClose.push_back(html::EndFontTag(html::FT_SIZE_LARGER)); + break; + case FONT_SIZE_LARGEST: + tagsToClose.push_back(html::EndFontTag(html::FT_SIZE_LARGEST)); + break; + case FONT_SIZE_HUGE: + tagsToClose.push_back(html::EndFontTag(html::FT_SIZE_HUGE)); + break; + case FONT_SIZE_HUGER: + tagsToClose.push_back(html::EndFontTag(html::FT_SIZE_HUGER)); + break; + case FONT_SIZE_INCREASE: + tagsToClose.push_back(html::EndFontTag(html::FT_SIZE_INCREASE)); + break; + case FONT_SIZE_DECREASE: + tagsToClose.push_back(html::EndFontTag(html::FT_SIZE_DECREASE)); + break; + case FONT_SIZE_INHERIT: + case FONT_SIZE_NORMAL: + break; + default: + // the other tags are for internal use + LATTEST(false); + break; + } + size_flag = false; + } + switch (curr_size) { + case FONT_SIZE_TINY: + tagsToOpen.push_back(html::FontTag(html::FT_SIZE_TINY)); + size_flag = true; + break; + case FONT_SIZE_SCRIPT: + tagsToOpen.push_back(html::FontTag(html::FT_SIZE_SCRIPT)); + size_flag = true; + break; + case FONT_SIZE_FOOTNOTE: + tagsToOpen.push_back(html::FontTag(html::FT_SIZE_FOOTNOTE)); + size_flag = true; + break; + case FONT_SIZE_SMALL: + tagsToOpen.push_back(html::FontTag(html::FT_SIZE_SMALL)); + size_flag = true; + break; + case FONT_SIZE_LARGE: + tagsToOpen.push_back(html::FontTag(html::FT_SIZE_LARGE)); + size_flag = true; + break; + case FONT_SIZE_LARGER: + tagsToOpen.push_back(html::FontTag(html::FT_SIZE_LARGER)); + size_flag = true; + break; + case FONT_SIZE_LARGEST: + tagsToOpen.push_back(html::FontTag(html::FT_SIZE_LARGEST)); + size_flag = true; + break; + case FONT_SIZE_HUGE: + tagsToOpen.push_back(html::FontTag(html::FT_SIZE_HUGE)); + size_flag = true; + break; + case FONT_SIZE_HUGER: + tagsToOpen.push_back(html::FontTag(html::FT_SIZE_HUGER)); + size_flag = true; + break; + case FONT_SIZE_INCREASE: + tagsToOpen.push_back(html::FontTag(html::FT_SIZE_INCREASE)); + size_flag = true; + break; + case FONT_SIZE_DECREASE: + tagsToOpen.push_back(html::FontTag(html::FT_SIZE_DECREASE)); + size_flag = true; + break; + case FONT_SIZE_NORMAL: + case FONT_SIZE_INHERIT: + break; + default: + // the other tags are for internal use + LATTEST(false); + break; } } + // FIXME XHTML // Other such tags? What about the other text ranges? + vector::const_iterator cit = tagsToClose.begin(); + vector::const_iterator cen = tagsToClose.end(); + for (; cit != cen; ++cit) + xs << *cit; + + vector::const_iterator sit = tagsToOpen.begin(); + vector::const_iterator sen = tagsToOpen.end(); + for (; sit != sen; ++sit) + xs << *sit; + + tagsToClose.clear(); + tagsToOpen.clear(); + Inset const * inset = getInset(i); if (inset) { if (!runparams.for_toc || inset->isInToc()) { OutputParams np = runparams; + np.local_font = &font; if (!inset->getLayout().htmlisblock()) np.html_in_par = true; retval += inset->xhtml(xs, np); } } else { - char_type c = d->text_[i]; + char_type c = getUChar(buf.masterBuffer()->params(), i); - if (style.pass_thru) + if (style.pass_thru || runparams.pass_thru) xs << c; else if (c == '-') { docstring str; @@ -3021,7 +3391,8 @@ void Paragraph::forToc(docstring & os, size_t maxlen) const } -docstring Paragraph::stringify(pos_type beg, pos_type end, int options, OutputParams & runparams) const +docstring Paragraph::stringify(pos_type beg, pos_type end, int options, + OutputParams const & runparams) const { odocstringstream os; @@ -3030,13 +3401,16 @@ docstring Paragraph::stringify(pos_type beg, pos_type end, int options, OutputPa && !d->params_.labelString().empty()) os << d->params_.labelString() << ' '; + OutputParams op = runparams; + op.for_search = true; + for (pos_type i = beg; i < end; ++i) { char_type const c = d->text_[i]; if (isPrintable(c) || c == '\t' || (c == '\n' && (options & AS_STR_NEWLINES))) os.put(c); else if (c == META_INSET && (options & AS_STR_INSETS)) { - getInset(i)->plaintext(os, runparams); + getInset(i)->plaintext(os, op); } } @@ -3097,8 +3471,7 @@ void Paragraph::setPlainOrDefaultLayout(DocumentClass const & tclass) Inset const & Paragraph::inInset() const { - LASSERT(d->inset_owner_, throw ExceptionMessage(BufferException, - _("Memory problem"), _("Paragraph not properly initialized"))); + LBUFERR(d->inset_owner_); return *d->inset_owner_; } @@ -3171,70 +3544,62 @@ char_type Paragraph::transformChar(char_type c, pos_type pos) const } -int Paragraph::checkBiblio(Buffer const & buffer) +bool Paragraph::brokenBiblio() const +{ + // there is a problem if there is no bibitem at position 0 or + // if there is another bibitem in the paragraph. + return d->layout_->labeltype == LABEL_BIBLIO + && (d->insetlist_.find(BIBITEM_CODE) != 0 + || d->insetlist_.find(BIBITEM_CODE, 1) > 0); +} + + +int Paragraph::fixBiblio(Buffer const & buffer) { - // FIXME From JS: - // This is getting more and more a mess. ...We really should clean - // up this bibitem issue for 1.6. + // FIXME: What about the case where paragraph is not BIBLIO + // but there is an InsetBibitem? + // FIXME: when there was already an inset at 0, the return value is 1, + // which does not tell whether another inset has been remove; the + // cursor cannot be correctly updated. - // Add bibitem insets if necessary if (d->layout_->labeltype != LABEL_BIBLIO) return 0; - bool hasbibitem = !d->insetlist_.empty() - // Insist on it being in pos 0 - && d->text_[0] == META_INSET - && d->insetlist_.begin()->inset->lyxCode() == BIBITEM_CODE; - - bool track_changes = buffer.params().trackChanges; - - docstring oldkey; - docstring oldlabel; - - // remove a bibitem in pos != 0 - // restore it later in pos 0 if necessary - // (e.g. if a user inserts contents _before_ the item) - // we're assuming there's only one of these, which there - // should be. - int erasedInsetPosition = -1; - InsetList::iterator it = d->insetlist_.begin(); - InsetList::iterator end = d->insetlist_.end(); - for (; it != end; ++it) - if (it->inset->lyxCode() == BIBITEM_CODE - && it->pos > 0) { - InsetCommand * olditem = it->inset->asInsetCommand(); - oldkey = olditem->getParam("key"); - oldlabel = olditem->getParam("label"); - erasedInsetPosition = it->pos; - eraseChar(erasedInsetPosition, track_changes); - break; - } + bool const track_changes = buffer.params().trackChanges; + int bibitem_pos = d->insetlist_.find(BIBITEM_CODE); + bool const hasbibitem0 = bibitem_pos == 0; - // There was an InsetBibitem at the beginning, and we didn't - // have to erase one. - if (hasbibitem && erasedInsetPosition < 0) + if (hasbibitem0) { + bibitem_pos = d->insetlist_.find(BIBITEM_CODE, 1); + // There was an InsetBibitem at pos 0, and no other one => OK + if (bibitem_pos == -1) return 0; + // there is a bibitem at the 0 position, but since + // there is a second one, we copy the second on the + // first. We're assuming there are at most two of + // these, which there should be. + // FIXME: why does it make sense to do that rather + // than keep the first? (JMarc) + Inset * inset = d->insetlist_.release(bibitem_pos); + eraseChar(bibitem_pos, track_changes); + d->insetlist_.begin()->inset = inset; + return -bibitem_pos; + } + + // We need to create an inset at the beginning + Inset * inset = 0; + if (bibitem_pos > 0) { + // there was one somewhere in the paragraph, let's move it + inset = d->insetlist_.release(bibitem_pos); + eraseChar(bibitem_pos, track_changes); + } else + // make a fresh one + inset = new InsetBibitem(const_cast(&buffer), + InsetCommandParams(BIBITEM_CODE)); - // There was an InsetBibitem at the beginning and we did have to - // erase one. So we give its properties to the beginning inset. - if (hasbibitem) { - InsetCommand * inset = d->insetlist_.begin()->inset->asInsetCommand(); - if (!oldkey.empty()) - inset->setParam("key", oldkey); - inset->setParam("label", oldlabel); - return -erasedInsetPosition; - } - - // There was no inset at the beginning, so we need to create one with - // the key and label of the one we erased. - InsetBibitem * inset = - new InsetBibitem(const_cast(&buffer), InsetCommandParams(BIBITEM_CODE)); - // restore values of previously deleted item in this par. - if (!oldkey.empty()) - inset->setParam("key", oldkey); - inset->setParam("label", oldlabel); - insertInset(0, inset, - Change(track_changes ? Change::INSERTED : Change::UNCHANGED)); + Font font(inherit_font, buffer.params().language); + insertInset(0, inset, font, Change(track_changes ? Change::INSERTED + : Change::UNCHANGED)); return 1; } @@ -3663,7 +4028,7 @@ SpellChecker::Result Paragraph::spellCheck(pos_type & from, pos_type & to, wl = WordLangTuple(word, lang); - if (!word.size()) + if (word.empty()) return result; if (needsSpellCheck() || check_learned) { @@ -3760,7 +4125,7 @@ void Paragraph::Private::markMisspelledWords( void Paragraph::spellCheck() const { SpellChecker * speller = theSpellChecker(); - if (!speller || !size() ||!needsSpellCheck()) + if (!speller || empty() ||!needsSpellCheck()) return; pos_type start; pos_type endpos;