]> git.lyx.org Git - lyx.git/blobdiff - src/Paragraph.cpp
Natbib authoryear uses (Ref1; Ref2) by default.
[lyx.git] / src / Paragraph.cpp
index 8126a2ffbfff54c42137560345a6189a4ff26a2c..72a26006322c93c1066e9b1dacc5462de6c87927 100644 (file)
@@ -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,7 +131,8 @@ private:
 
 class SpellCheckerState {
 public:
-       SpellCheckerState() {
+       SpellCheckerState()
+       {
                needs_refresh_ = true;
                current_change_number_ = 0;
        }
@@ -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<SpellResultRange> Ranges;
        typedef Ranges::const_iterator RangesIterator;
@@ -384,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();
@@ -405,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);
        }
 
@@ -575,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);
 }
@@ -592,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);
 }
@@ -638,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
@@ -650,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) {
@@ -692,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) {
@@ -728,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);
@@ -757,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.
@@ -768,13 +778,15 @@ 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;
 }
 
@@ -836,8 +848,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) {
@@ -859,7 +871,13 @@ 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).first;
+       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
@@ -1027,10 +1045,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;
        }
 
@@ -1358,16 +1378,19 @@ 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*/)
+       pos_type /*i*/, unsigned int & column)
 {
        switch (c) {
        case '*':
        case '[':
        case ']':
-       case '|':
        case '\"':
                os.put(c);
                return true;
+       case '|':
+               os << "\\textvertline{}";
+               column += 14;
+               return true;
        default:
                return false;
        }
@@ -1442,18 +1465,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);
                }
@@ -1755,12 +1785,10 @@ void Paragraph::insertChar(pos_type pos, char_type c,
 
 
 bool Paragraph::insertInset(pos_type pos, Inset * inset,
-                           Font const & font, Change const & change)
+                           Change const & change)
 {
-       bool const success = insertInset(pos, inset, change);
-       // Set the font/language of the inset...
-       setFont(pos, font);
-       return success;
+       Font no_font;
+       return insertInset(pos, inset, no_font, change);
 }
 
 
@@ -1777,7 +1805,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);
@@ -1802,9 +1830,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) {
@@ -1821,8 +1849,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));
 }
 
 
@@ -1853,7 +1881,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);
 
@@ -1910,8 +1938,8 @@ char_type Paragraph::getUChar(BufferParams const & bparams, pos_type pos) const
        // 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";
+       bool const arabic = lang == "arabic_arabtex" || lang == "arabic_arabi"
+               || lang == "farsi";
        char_type uc = c;
        switch (c) {
        case '(':
@@ -1946,7 +1974,7 @@ char_type Paragraph::getUChar(BufferParams const & bparams, pos_type pos) const
 
 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
@@ -2058,8 +2086,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',
@@ -2150,7 +2177,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 {
@@ -2409,6 +2436,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);
        }
@@ -2439,6 +2470,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);
@@ -2629,6 +2665,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;
@@ -2790,6 +2831,22 @@ void Paragraph::simpleDocBookOnePar(Buffer const & buf,
 }
 
 
+namespace {
+void doFontSwitch(vector<html::FontTag> & tagsToOpen,
+                  vector<html::EndFontTag> & 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,
@@ -2798,65 +2855,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<html::FontTag> tagsToOpen;
+       vector<html::EndFontTag> 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<html::EndFontTag>::const_iterator cit = tagsToClose.begin();
+               vector<html::EndFontTag>::const_iterator cen = tagsToClose.end();
+               for (; cit != cen; ++cit)
+                       xs << *cit;
+
+               vector<html::FontTag>::const_iterator sit = tagsToOpen.begin();
+               vector<html::FontTag>::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;
@@ -3091,7 +3400,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;
 
@@ -3100,13 +3410,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);
                }
        }
 
@@ -3167,8 +3480,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_;
 }
 
@@ -3724,7 +4036,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) {
@@ -3821,7 +4133,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;