#include "BufferParams.h"
#include "Changes.h"
#include "Counters.h"
-#include "Encoding.h"
+#include "BufferEncodings.h"
#include "InsetList.h"
#include "Language.h"
#include "LaTeXFeatures.h"
TextContainer text_;
typedef set<docstring> Words;
- typedef map<Language, Words> LangWordsMap;
+ typedef map<string, Words> LangWordsMap;
///
LangWordsMap words_;
///
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);
}
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);
}
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
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) {
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) {
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);
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.
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;
}
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) {
unsigned int & column)
{
Inset * inset = owner_->getInset(i);
- LASSERT(inset, /**/);
+ LBUFERR(inset);
if (style.pass_thru) {
odocstringstream ods;
docstring nextlatex;
bool nexttipas = false;
string nexttipashortcut;
- if (next != '\0' && next != META_INSET) {
+ if (next != '\0' && next != META_INSET && encoding.encodable(next)) {
nextlatex = encoding.latexChar(next).first;
if (runparams.inIPA) {
nexttipashortcut = Encodings::TIPAShortcut(next);
if (layout_->inpreamble && inset_owner_) {
bool const is_command = layout_->latextype == LATEX_COMMAND;
Buffer const & buf = inset_owner_->buffer();
- BufferParams const & bp = buf.params();
+ BufferParams const & bp = features.runparams().is_child
+ ? buf.masterParams() : buf.params();
Font f;
TexRow texrow;
// Using a string stream here circumvents the encoding
break;
}
}
- Encodings::validate(text_[i], features);
+ BufferEncodings::validate(text_[i], features);
}
}
}
-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();
{
if (pos > size()) {
LYXERR0("pos: " << pos << " size: " << size());
- LASSERT(pos <= size(), /**/);
+ LBUFERR(false);
}
FontList::const_iterator cit = d->fontlist_.fontIterator(pos);
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) {
}
// 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));
}
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);
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
Change const & change = runparams.inDeletedInset
? runparams.changeOfDeletedInset : lookupChange(i);
- if (bparams.outputChanges && runningChange != change) {
+ if (bparams.output_changes && runningChange != change) {
if (open_font) {
column += running_font.latexWriteEndChanges(
os, bparams, runparams, basefont, basefont);
// do not output text which is marked deleted
// if change tracking output is disabled
- if (!bparams.outputChanges && change.deleted()) {
+ if (!bparams.output_changes && change.deleted()) {
continue;
}
}
+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,
{
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 = getUChar(buf.params(), i);
+ char_type c = getUChar(buf.masterBuffer()->params(), i);
if (style.pass_thru || runparams.pass_thru)
xs << c;
}
-docstring Paragraph::asString(pos_type beg, pos_type end, int options) const
+docstring Paragraph::asString(pos_type beg, pos_type end, int options, const OutputParams *runparams) const
{
odocstringstream os;
|| (c == '\n' && (options & AS_STR_NEWLINES)))
os.put(c);
else if (c == META_INSET && (options & AS_STR_INSETS)) {
- getInset(i)->toString(os);
- if (getInset(i)->asInsetMath())
- os << " ";
+ if (c == META_INSET && (options & AS_STR_PLAINTEXT)) {
+ LASSERT(runparams != 0, return docstring());
+ getInset(i)->plaintext(os, *runparams);
+ } else {
+ getInset(i)->toString(os);
+ if (getInset(i)->asInsetMath())
+ os << " ";
+ }
}
}
}
-void Paragraph::forToc(docstring & os, size_t maxlen) const
+void Paragraph::forOutliner(docstring & os, size_t maxlen) const
{
if (!d->params_.labelString().empty())
os += d->params_.labelString() + ' ';
else if (c == '\t' || c == '\n')
os += ' ';
else if (c == META_INSET)
- getInset(i)->forToc(os, maxlen);
+ getInset(i)->forOutliner(os, maxlen);
}
}
-docstring Paragraph::stringify(pos_type beg, pos_type end, int options,
- OutputParams const & runparams) const
-{
- odocstringstream os;
-
- if (beg == 0
- && options & AS_STR_LABEL
- && !d->params_.labelString().empty())
- os << d->params_.labelString() << ' ';
-
- 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);
- }
- }
-
- return os.str();
-}
-
-
void Paragraph::setInsetOwner(Inset const * inset)
{
d->inset_owner_ = inset;
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_;
}
if (d->layout_->labeltype != LABEL_BIBLIO)
return 0;
- bool const track_changes = buffer.params().trackChanges;
+ bool const track_changes = buffer.params().track_changes;
int bibitem_pos = d->insetlist_.find(BIBITEM_CODE);
bool const hasbibitem0 = bibitem_pos == 0;
// 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);
+ Inset * inset = releaseInset(bibitem_pos);
d->insetlist_.begin()->inset = inset;
return -bibitem_pos;
}
inset = new InsetBibitem(const_cast<Buffer *>(&buffer),
InsetCommandParams(BIBITEM_CODE));
- insertInset(0, inset, Change(track_changes ? Change::INSERTED
+ Font font(inherit_font, buffer.params().language);
+ insertInset(0, inset, font, Change(track_changes ? Change::INSERTED
: Change::UNCHANGED));
return 1;
// process sequences of modified characters; in change
// tracking mode, this approach results in much better
// usability than changing case on a char-by-char basis
- docstring changes;
+ // We also need to track the current font, since font
+ // changes within sequences can occur.
+ vector<pair<char_type, Font> > changes;
- bool const trackChanges = bparams.trackChanges;
+ bool const trackChanges = bparams.track_changes;
bool capitalize = true;
}
if (oldChar != newChar) {
- changes += newChar;
+ changes.push_back(make_pair(newChar, getFontSettings(bparams, pos)));
if (pos != right - 1)
continue;
// step behind the changing area
int erasePos = pos - changes.size();
for (size_t i = 0; i < changes.size(); i++) {
- insertChar(pos, changes[i],
- getFontSettings(bparams,
- erasePos),
+ insertChar(pos, changes[i].first,
+ changes[i].second,
trackChanges);
if (!eraseChar(erasePos, trackChanges)) {
++erasePos;
if (cit == d->fontlist_.end())
return;
Language const * lang = cit->font().language();
- d->words_[*lang].insert(word);
+ d->words_[lang->lang()].insert(word);
}
}
}