return end - i;
}
-
+// Handle combining characters
int Paragraph::Private::latexSurrogatePair(BufferParams const & bparams,
otexstream & os, char_type c, char_type next,
OutputParams const & runparams)
}
docstring latex2 = encoding.latexChar(c).first;
- if (docstring(1, next) == latex1) {
- // The encoding supports the combination:
+ // Handle combining characters in "script" context (i.e., \textgreek and \textcyrillic)
+ docstring::size_type const brace1 = latex2.find_first_of(from_ascii("{"));
+ docstring::size_type const brace2 = latex2.find_last_of(from_ascii("}"));
+ string script = to_ascii(latex2.substr(1, brace1 - 1));
+
+ // Greek and Cyrillic letters need to be wrapped in \textcyrillic and \textgreek if they
+ // are not encodable in the current font encoding (regardless of the input encoding).
+ bool scriptchar = false;
+ if (!bparams.useNonTeXFonts) // With non-TeX fonts the font encoding is Unicode.
+ scriptchar = Encodings::isKnownScriptChar(c, script);
+
+ if (!scriptchar && docstring(1, next) == latex1) {
+ // Font and input encoding support the combination:
// output as is (combining char after base char).
os << latex2 << latex1;
return latex1.length() + latex2.length();
}
- // Handle combining characters in "script" context (i.e., \textgreek and \textcyrillic)
- docstring::size_type const brace1 = latex2.find_first_of(from_ascii("{"));
- docstring::size_type const brace2 = latex2.find_last_of(from_ascii("}"));
- string script = to_ascii(latex2.substr(1, brace1 - 1));
- // "Script chars" need to embraced in \textcyrillic and \textgreek notwithstanding
- // whether they are encodable or not (it only depends on the font encoding)
- if (!runparams.isFullUnicode())
- // This will get us a script value to deal with below
- Encodings::isKnownScriptChar(c, script);
int pos = 0;
int length = brace2;
string fontenc;
if (runparams.local_font)
fontenc = runparams.local_font->language()->fontenc(bparams);
else
- fontenc = runparams.main_fontenc;
+ fontenc = bparams.language->fontenc(bparams);
docstring scriptmacro;
docstring cb;
if (script == "textgreek" || script == "textcyrillic") {
- // We separate the script macro (\text[greek|cyr]) from the rest,
- // since we need to include the combining char in it (#6463).
- // This is "the rest":
+ // Strip the \text(greek|cyrillic) script macro ...
pos = brace1 + 1;
length -= pos;
latex2 = latex2.substr(pos, length);
- // We only need the script macro with non-native font encodings
+ // and place it before the accent macro if required (#6463)
if (Encodings::needsScriptWrapper(script, fontenc)) {
scriptmacro = from_ascii("\\" + script + "{");
cb = from_ascii("}");
}
}
- docstring lb;
- docstring rb;
- // polutonikogreek does not play nice with brackets
- if (!runparams.local_font
- || runparams.local_font->language()->lang() != "polutonikogreek") {
- lb = from_ascii("{");
- rb = from_ascii("}");
- }
-
- os << scriptmacro << latex1 << lb << latex2 << rb << cb;
- return latex1.length() + latex2.length() + lb.length() + rb.length() + cb.length();
+ os << scriptmacro << latex1 << "{" << latex2 << "}" << cb;
+ return latex1.length() + 1 + latex2.length() + 1 + cb.length();
}
int pos = 0;
int length = brace2;
bool closing_brace = true;
+ // We only need the script macro with non-native font encodings
if (!Encodings::needsScriptWrapper(script, fontenc)) {
- // Correct font encoding is being used, so we can avoid \text[greek|cyr].
+ // Correct font encoding is being used, so we can avoid \text(greek|cyrrillic).
pos = brace1 + 1;
length -= pos;
closing_brace = false;
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
&& inset->lyxCode() != ERT_CODE) {
- if (running_font.language()->lang() == "farsi")
- os << "\\beginL" << termcmd;
+ if (runparams.use_polyglossia) {
+ os << "\\LRE{";
+ } else if (running_font.language()->lang() == "farsi"
+ || running_font.language()->lang() == "arabic_arabi")
+ os << "\\textLR{" << termcmd;
else
os << "\\L{";
close = true;
throw(e);
}
- if (close) {
- if (running_font.language()->lang() == "farsi")
- os << "\\endL" << termcmd;
- else
- os << '}';
- }
+ if (close)
+ os << '}';
if (os.texrow().rows() > previous_row_count) {
os.texrow().start(owner_->id(), i + 1);
pos_type end_pos,
unsigned int & column)
{
- // 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];
+ char_type const c = owner_->getUChar(bparams, runparams, i);
if (style.pass_thru || runparams.pass_thru
|| contains(style.pass_thru_chars, c)
}
}
string fontenc;
- if (running_font.language()->lang() == bparams.language->lang())
- fontenc = runparams.main_fontenc;
- else
- fontenc = running_font.language()->fontenc(bparams);
+ fontenc = running_font.language()->fontenc(bparams);
// "Script chars" need to embraced in \textcyrillic and \textgreek notwithstanding
- // whether they are encodable or not (it only depends on the font encoding)
- if (!runparams.isFullUnicode() && Encodings::isKnownScriptChar(c, script)) {
+ // whether they are encodable or not (it only depends on the font encoding),
+ // except if we are using fontspec.
+ if (!bparams.useNonTeXFonts && Encodings::isKnownScriptChar(c, script)) {
docstring const wrapper = from_ascii("\\" + script + "{");
docstring ltx = latex.first;
if (!prefixIs(ltx, wrapper))
void Paragraph::validate(LaTeXFeatures & features) const
{
d->validate(features);
- if (needsCProtection())
+ bool fragile = features.runparams().moving_arg;
+ fragile |= layout().needprotect;
+ if (needsCProtection(fragile))
features.require("cprotect");
}
}
-char_type Paragraph::getUChar(BufferParams const & bparams, pos_type pos) const
+char_type Paragraph::getUChar(BufferParams const & bparams,
+ OutputParams const & rp,
+ pos_type pos) const
{
char_type c = d->text_[pos];
- if (!getFontSettings(bparams, pos).isRightToLeft())
+
+ // Return unchanged character in LTR languages
+ // or if we use poylglossia/bidi.
+ if (rp.use_polyglossia || !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).
+ // Without polyglossia/bidi, we need to account for some special cases.
+ // FIXME This needs to be audited!
+ // Check if:
+ // * The input is as expected for all delimiters
+ // => checked for Hebrew!
+ // * The output matches the display in the LyX workarea
+ // => checked for Hebrew!
+ // * The special cases below are really necessary
+ // => checked for Hebrew!
+ // * In arabic_arabi, brackets are transformed to Arabic
+ // Ornate Parentheses. Is this is really wanted?
+
string const & lang = getFontSettings(bparams, pos).language()->lang();
- bool const arabic = lang == "arabic_arabtex" || lang == "arabic_arabi"
- || lang == "farsi";
char_type uc = c;
+
+ // 1. In the following languages, parentheses need to be reversed.
+ bool const reverseparens = lang == "hebrew";
+
+ // 2. In the following languages, brackets don't need to be reversed.
+ bool const reversebrackets = lang != "arabic_arabtex"
+ && lang != "arabic_arabi"
+ && lang != "farsi";
+
+ // Now swap delimiters if needed.
switch (c) {
case '(':
- uc = arabic ? c : ')';
+ if (reverseparens)
+ uc = ')';
break;
case ')':
- uc = arabic ? c : '(';
+ if (reverseparens)
+ uc = '(';
break;
case '[':
- uc = ']';
+ if (reversebrackets)
+ uc = ']';
break;
case ']':
- uc = '[';
+ if (reversebrackets)
+ uc = '[';
break;
case '{':
uc = '}';
string const begin_tag = "\\begin";
InsetCode code = ownerCode();
bool const lastpar = runparams.isLastPar;
+ // RTL in classic (PDF)LaTeX (without the Bidi package)
+ bool const rtl_classic = owner_->getParLanguage(bparams)->rightToLeft()
+ && !runparams.use_polyglossia;
switch (curAlign) {
case LYX_ALIGN_NONE:
case LYX_ALIGN_DECIMAL:
break;
case LYX_ALIGN_LEFT: {
- if (owner_->getParLanguage(bparams)->babel() != "hebrew")
- corrected_env(os, begin_tag, "flushleft", code, lastpar, column);
- else
+ if (rtl_classic)
+ // Classic (PDF)LaTeX switches the left/right logic in RTL mode
corrected_env(os, begin_tag, "flushright", code, lastpar, column);
+ else
+ corrected_env(os, begin_tag, "flushleft", code, lastpar, column);
break;
} case LYX_ALIGN_RIGHT: {
- if (owner_->getParLanguage(bparams)->babel() != "hebrew")
- corrected_env(os, begin_tag, "flushright", code, lastpar, column);
- else
+ if (rtl_classic)
+ // Classic (PDF)LaTeX switches the left/right logic in RTL mode
corrected_env(os, begin_tag, "flushleft", code, lastpar, column);
+ else
+ corrected_env(os, begin_tag, "flushright", code, lastpar, column);
break;
} case LYX_ALIGN_CENTER: {
corrected_env(os, begin_tag, "center", code, lastpar, column);
string const end_tag = "\\par\\end";
InsetCode code = ownerCode();
bool const lastpar = runparams.isLastPar;
+ // RTL in classic (PDF)LaTeX (without the Bidi package)
+ bool const rtl_classic = owner_->getParLanguage(bparams)->rightToLeft()
+ && !runparams.use_polyglossia;
switch (curAlign) {
case LYX_ALIGN_NONE:
case LYX_ALIGN_DECIMAL:
break;
case LYX_ALIGN_LEFT: {
- if (owner_->getParLanguage(bparams)->babel() != "hebrew")
- output = corrected_env(os, end_tag, "flushleft", code, lastpar, col);
- else
+ if (rtl_classic)
+ // Classic (PDF)LaTeX switches the left/right logic in RTL mode
output = corrected_env(os, end_tag, "flushright", code, lastpar, col);
+ else
+ output = corrected_env(os, end_tag, "flushleft", code, lastpar, col);
break;
} case LYX_ALIGN_RIGHT: {
- if (owner_->getParLanguage(bparams)->babel() != "hebrew")
- output = corrected_env(os, end_tag, "flushright", code, lastpar, col);
- else
+ if (rtl_classic)
+ // Classic (PDF)LaTeX switches the left/right logic in RTL mode
output = corrected_env(os, end_tag, "flushleft", code, lastpar, col);
+ else
+ output = corrected_env(os, end_tag, "flushright", code, lastpar, col);
break;
} case LYX_ALIGN_CENTER: {
corrected_env(os, end_tag, "center", code, lastpar, col);
retval += inset->xhtml(xs, np);
}
} else {
- char_type c = getUChar(buf.masterBuffer()->params(), i);
- xs << c;
+ char_type c = getUChar(buf.masterBuffer()->params(),
+ runparams, i);
+ if (c == ' ' && (style.free_spacing || runparams.free_spacing))
+ xs << XHTMLStream::ESCAPE_NONE << " ";
+ else
+ xs << c;
}
font_old = font.fontInfo();
}
}
-bool Paragraph::needsCProtection() const
+bool Paragraph::needsCProtection(bool const fragile) const
{
// first check the layout of the paragraph, but only in insets
InsetText const * textinset = inInset().asInsetText();
// now check whether we have insets that need cprotection
pos_type size = d->text_.size();
for (pos_type i = 0; i < size; ++i)
- if (isInset(i) && getInset(i)->needsCProtection(maintext))
+ if (isInset(i) && getInset(i)->needsCProtection(maintext, fragile))
return true;
return false;
docstring word = asString(from, to, AS_STR_INSETS | AS_STR_SKIPDELETE);
Language * lang = d->getSpellLanguage(from);
+ if (getFontSettings(d->inset_owner_->buffer().params(), from).fontInfo().nospellcheck() == FONT_ON)
+ return result;
+
wl = WordLangTuple(word, lang);
if (word.empty())