X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Finsets%2FInsetSpecialChar.cpp;h=5983c07d649906ad69c225ae005c2b8c2fa801a5;hb=8124e6c02ea1fd6779bb6c47ffe2bca2c8bd2d97;hp=dd2ebff3d29b3503290e18a22bba39a026f83a0e;hpb=3a7346b0cbbd2b9f030cdff551bb03225faffd87;p=lyx.git diff --git a/src/insets/InsetSpecialChar.cpp b/src/insets/InsetSpecialChar.cpp index dd2ebff3d2..5983c07d64 100644 --- a/src/insets/InsetSpecialChar.cpp +++ b/src/insets/InsetSpecialChar.cpp @@ -15,12 +15,14 @@ #include "InsetSpecialChar.h" #include "Dimension.h" +#include "Encoding.h" #include "Font.h" #include "Language.h" #include "LaTeXFeatures.h" #include "Lexer.h" #include "MetricsInfo.h" #include "output_xhtml.h" +#include "xml.h" #include "texstream.h" #include "frontends/FontMetrics.h" @@ -36,7 +38,7 @@ namespace lyx { InsetSpecialChar::InsetSpecialChar(Kind k) - : Inset(0), kind_(k) + : Inset(nullptr), kind_(k) {} @@ -81,6 +83,29 @@ docstring InsetSpecialChar::toolTip(BufferView const &, int, int) const } +int InsetSpecialChar::rowFlags() const +{ + switch (kind_) { + case ALLOWBREAK: + case HYPHENATION: + case SLASH: + // these are the elements that allow line breaking + return CanBreakAfter; + case NOBREAKDASH: + case END_OF_SENTENCE: + case LIGATURE_BREAK: + case LDOTS: + case MENU_SEPARATOR: + case PHRASE_LYX: + case PHRASE_TEX: + case PHRASE_LATEX2E: + case PHRASE_LATEX: + break; + } + return Inline; +} + + namespace { // helper function: draw text and update x. @@ -130,6 +155,7 @@ void drawLogo(PainterInfo & pi, int & x, int const y, InsetSpecialChar::Kind kin drawLogo(pi, x, y, InsetSpecialChar::PHRASE_LATEX); x += 3 * em / 20; drawChar(pi, x, y, '2'); + // ε U+03B5 GREEK SMALL LETTER EPSILON drawChar(pi, x, y + em / 4, char_type(0x03b5)); break; @@ -165,8 +191,7 @@ void drawLogo(PainterInfo & pi, int & x, int const y, InsetSpecialChar::Kind kin void InsetSpecialChar::metrics(MetricsInfo & mi, Dimension & dim) const { - frontend::FontMetrics const & fm = - theFontMetrics(mi.base.font); + frontend::FontMetrics const & fm = theFontMetrics(mi.base.font); dim.asc = fm.maxAscent(); dim.des = 0; dim.wid = 0; @@ -184,9 +209,14 @@ void InsetSpecialChar::metrics(MetricsInfo & mi, Dimension & dim) const case END_OF_SENTENCE: s = from_ascii("."); break; - case LDOTS: - s = from_ascii(". . ."); + case LDOTS: { + // see comment in draw(). + auto const fam = mi.base.font.family(); + // Multiplication by 3 is done here to limit rounding effects. + int const spc3 = fam == TYPEWRITER_FAMILY ? 0 : 3 * fm.width(char_type(' ')) / 2; + dim.wid = 3 * fm.width(char_type('.')) + spc3; break; + } case MENU_SEPARATOR: // ▹ U+25B9 WHITE RIGHT-POINTING SMALL TRIANGLE // There is a \thinspace on each side of the triangle @@ -259,15 +289,22 @@ void InsetSpecialChar::draw(PainterInfo & pi, int x, int y) const case LDOTS: { font.setColor(Color_special); - string ell = ". . . "; - docstring dell(ell.begin(), ell.end()); - pi.pain.text(x, y, dell, font); + /* \textellipsis uses a \fontdimen3 is spacing. The TeXbook + * tells us that \fontdimen3 is the interword stretch, and + * that this is usually half a space. + */ + frontend::FontMetrics const & fm = theFontMetrics(font); + auto const fam = pi.base.font.family(); + int const spc = fam == TYPEWRITER_FAMILY ? 0 : fm.width(char_type(' ')) / 2; + int wid1 = fm.width(char_type('.')) + spc; + pi.pain.text(x, y, char_type('.'), font); + pi.pain.text(x + wid1, y, char_type('.'), font); + pi.pain.text(x + 2 * wid1, y, char_type('.'), font); break; } case MENU_SEPARATOR: { - frontend::FontMetrics const & fm = - theFontMetrics(font); + frontend::FontMetrics const & fm = theFontMetrics(font); // There is a \thinspace on each side of the triangle x += fm.em() / 6; @@ -383,6 +420,7 @@ void InsetSpecialChar::latex(otexstream & os, OutputParams const & rp) const { bool const rtl = rp.local_font->isRightToLeft(); + bool const utf8 = rp.encoding->iconvName() == "UTF-8"; string lswitch = ""; string lswitche = ""; if (rtl && !rp.use_polyglossia) { @@ -398,10 +436,15 @@ void InsetSpecialChar::latex(otexstream & os, os << "\\-"; break; case ALLOWBREAK: + // U+200B not yet supported by utf8 inputenc os << "\\LyXZeroWidthSpace" << termcmd; break; case LIGATURE_BREAK: - os << "\\textcompwordmark" << termcmd; + if (utf8) + // U+200C ZERO WIDTH NON-JOINER + os.put(0x200c); + else + os << "\\textcompwordmark" << termcmd; break; case END_OF_SENTENCE: os << "\\@."; @@ -455,15 +498,18 @@ int InsetSpecialChar::plaintext(odocstringstream & os, case HYPHENATION: return 0; case ALLOWBREAK: + // U+200B ZERO WIDTH SPACE (ZWSP) os.put(0x200b); return 1; case LIGATURE_BREAK: + // U+200C ZERO WIDTH NON-JOINER os.put(0x200c); return 1; case END_OF_SENTENCE: os << '.'; return 1; case LDOTS: + // … U+2026 HORIZONTAL ELLIPSIS os.put(0x2026); return 1; case MENU_SEPARATOR: @@ -473,6 +519,7 @@ int InsetSpecialChar::plaintext(odocstringstream & os, os << '/'; return 1; case NOBREAKDASH: + // ‑ U+2011 NON-BREAKING HYPHEN os.put(0x2011); return 1; case PHRASE_LYX: @@ -483,6 +530,7 @@ int InsetSpecialChar::plaintext(odocstringstream & os, return 3; case PHRASE_LATEX2E: os << "LaTeX2"; + // ε U+03B5 GREEK SMALL LETTER EPSILON os.put(0x03b5); return 7; case PHRASE_LATEX: @@ -493,88 +541,57 @@ int InsetSpecialChar::plaintext(odocstringstream & os, } -int InsetSpecialChar::docbook(odocstream & os, OutputParams const &) const -{ - switch (kind_) { - case HYPHENATION: - break; - case ALLOWBREAK: - os.put(0x200b); - break; - case LIGATURE_BREAK: - break; - case END_OF_SENTENCE: - os << '.'; - break; - case LDOTS: - os << "…"; - break; - case MENU_SEPARATOR: - os << "&lyxarrow;"; - break; - case SLASH: - os << '/'; - break; - case NOBREAKDASH: - os << '-'; - break; - case PHRASE_LYX: - os << "LyX"; - break; - case PHRASE_TEX: - os << "TeX"; - break; - case PHRASE_LATEX2E: - os << "LaTeX2"; - os.put(0x03b5); - break; - case PHRASE_LATEX: - os << "LaTeX"; - break; +namespace { +string specialCharKindToXMLEntity(InsetSpecialChar::Kind kind) { + switch (kind) { + case InsetSpecialChar::Kind::HYPHENATION: + // Soft hyphen. + return "­"; + case InsetSpecialChar::Kind::ALLOWBREAK: + // Zero-width space + return "​"; + case InsetSpecialChar::Kind::LIGATURE_BREAK: + // Zero width non-joiner + return "‌"; + case InsetSpecialChar::Kind::END_OF_SENTENCE: + return "."; + case InsetSpecialChar::Kind::LDOTS: + // … + return "…"; + case InsetSpecialChar::Kind::MENU_SEPARATOR: + // ⇒, right arrow. + return "⇒"; + case InsetSpecialChar::Kind::SLASH: + // ⁄, fractional slash. + return "⁄"; + case InsetSpecialChar::Kind::NOBREAKDASH: + // Non-breaking hyphen. + return "‑"; + case InsetSpecialChar::Kind::PHRASE_LYX: + return "LyX"; + case InsetSpecialChar::Kind::PHRASE_TEX: + return "TeX"; + case InsetSpecialChar::Kind::PHRASE_LATEX2E: + // Lower-case epsilon. + return "LaTeX2ε"; + case InsetSpecialChar::Kind::PHRASE_LATEX: + return "LaTeX"; + default: + return ""; } - return 0; +} } -docstring InsetSpecialChar::xhtml(XHTMLStream & xs, OutputParams const &) const +void InsetSpecialChar::docbook(XMLStream & xs, OutputParams const &) const { - switch (kind_) { - case HYPHENATION: - break; - case ALLOWBREAK: - xs << XHTMLStream::ESCAPE_NONE << "​"; - break; - case LIGATURE_BREAK: - xs << XHTMLStream::ESCAPE_NONE << "‌"; - break; - case END_OF_SENTENCE: - xs << '.'; - break; - case LDOTS: - xs << XHTMLStream::ESCAPE_NONE << "…"; - break; - case MENU_SEPARATOR: - xs << XHTMLStream::ESCAPE_NONE << "⇒"; - break; - case SLASH: - xs << XHTMLStream::ESCAPE_NONE << "⁄"; - break; - case NOBREAKDASH: - xs << XHTMLStream::ESCAPE_NONE << "‑"; - break; - case PHRASE_LYX: - xs << "LyX"; - break; - case PHRASE_TEX: - xs << "TeX"; - break; - case PHRASE_LATEX2E: - xs << "LaTeX2" << XHTMLStream::ESCAPE_NONE << "ε"; - break; - case PHRASE_LATEX: - xs << "LaTeX"; - break; - } + xs << XMLStream::ESCAPE_NONE << from_ascii(specialCharKindToXMLEntity(kind_)); +} + + +docstring InsetSpecialChar::xhtml(XMLStream & xs, OutputParams const &) const +{ + xs << XMLStream::ESCAPE_NONE << from_ascii(specialCharKindToXMLEntity(kind_)); return docstring(); } @@ -591,7 +608,7 @@ void InsetSpecialChar::toString(odocstream & os) const break; } odocstringstream ods; - plaintext(ods, OutputParams(0)); + plaintext(ods, OutputParams(nullptr)); os << ods.str(); } @@ -600,7 +617,7 @@ void InsetSpecialChar::forOutliner(docstring & os, size_t const, bool const) const { odocstringstream ods; - plaintext(ods, OutputParams(0)); + plaintext(ods, OutputParams(nullptr)); os += ods.str(); } @@ -627,7 +644,9 @@ bool InsetSpecialChar::isChar() const bool InsetSpecialChar::isLetter() const { return kind_ == HYPHENATION || kind_ == LIGATURE_BREAK - || kind_ == NOBREAKDASH; + || kind_ == NOBREAKDASH + || kind_ == PHRASE_LYX || kind_ == PHRASE_LATEX + || kind_ == PHRASE_TEX || kind_ == PHRASE_LATEX2E; }