3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Lars Gullik Bjønnes
7 * \author Jean-Marc Lasgouttes
8 * \author Angus Leeming
12 * Full author contact details are available in file CREDITS.
19 #include "BufferParams.h" // stateText
23 #include "LaTeXFeatures.h"
26 #include "output_latex.h"
27 #include "OutputParams.h"
29 #include "support/lassert.h"
30 #include "support/convert.h"
31 #include "support/debug.h"
32 #include "support/gettext.h"
33 #include "support/lstrings.h"
38 using namespace lyx::support
;
43 // Strings used to read and write .lyx format files
45 // These are defined in FontInfo.cpp
46 extern char const * LyXFamilyNames
[NUM_FAMILIES
+ 2];
47 extern char const * LyXSeriesNames
[4];
48 extern char const * LyXShapeNames
[6];
49 extern char const * LyXSizeNames
[14];
50 extern char const * LyXMiscNames
[5];
58 char const * GUIFamilyNames
[NUM_FAMILIES
+ 2 /* default & error */] =
59 { N_("Roman"), N_("Sans Serif"), N_("Typewriter"), N_("Symbol"),
60 "cmr", "cmsy", "cmm", "cmex", "msa", "msb", "eufrak", "wasy", "esint",
61 N_("Inherit"), N_("Ignore") };
63 char const * GUISeriesNames
[4] =
64 { N_("Medium"), N_("Bold"), N_("Inherit"), N_("Ignore") };
66 char const * GUIShapeNames
[6] =
67 { N_("Upright"), N_("Italic"), N_("Slanted"), N_("Smallcaps"), N_("Inherit"),
70 char const * GUISizeNames
[14] =
71 { N_("Tiny"), N_("Smallest"), N_("Smaller"), N_("Small"), N_("Normal"), N_("Large"),
72 N_("Larger"), N_("Largest"), N_("Huge"), N_("Huger"), N_("Increase"), N_("Decrease"),
73 N_("Inherit"), N_("Ignore") };
75 char const * GUIMiscNames
[5] =
76 { N_("Off"), N_("On"), N_("Toggle"), N_("Inherit"), N_("Ignore") };
79 // Strings used to write LaTeX files
81 char const * LaTeXFamilyNames
[6] =
82 { "textrm", "textsf", "texttt", "error1", "error2", "error3" };
84 char const * LaTeXSeriesNames
[4] =
85 { "textmd", "textbf", "error4", "error5" };
87 char const * LaTeXShapeNames
[6] =
88 { "textup", "textit", "textsl", "textsc", "error6", "error7" };
90 char const * LaTeXSizeNames
[14] =
91 { "tiny", "scriptsize", "footnotesize", "small", "normalsize", "large",
92 "Large", "LARGE", "huge", "Huge", "error8", "error9", "error10", "error11" };
97 Font::Font(FontInfo bits
, Language
const * l
)
98 : bits_(bits
), lang_(l
), misspelled_(false), open_encoding_(false)
101 lang_
= default_language
;
105 bool Font::isRightToLeft() const
107 return lang_
->rightToLeft();
111 bool Font::isVisibleRightToLeft() const
113 return (lang_
->rightToLeft() &&
114 bits_
.number() != FONT_ON
);
118 void Font::setLanguage(Language
const * l
)
124 /// Updates font settings according to request
125 void Font::update(Font
const & newfont
,
126 Language
const * document_language
,
129 bits_
.update(newfont
.fontInfo(), toggleall
);
131 if (newfont
.language() == language() && toggleall
)
132 if (language() == document_language
)
133 setLanguage(default_language
);
135 setLanguage(document_language
);
136 else if (newfont
.language() == reset_language
)
137 setLanguage(document_language
);
138 else if (newfont
.language() != ignore_language
)
139 setLanguage(newfont
.language());
143 docstring
const stateText(FontInfo
const & f
)
146 if (f
.family() != INHERIT_FAMILY
)
147 os
<< _(GUIFamilyNames
[f
.family()]) << ", ";
148 if (f
.series() != INHERIT_SERIES
)
149 os
<< _(GUISeriesNames
[f
.series()]) << ", ";
150 if (f
.shape() != INHERIT_SHAPE
)
151 os
<< _(GUIShapeNames
[f
.shape()]) << ", ";
152 if (f
.size() != FONT_SIZE_INHERIT
)
153 os
<< _(GUISizeNames
[f
.size()]) << ", ";
154 if (f
.color() != Color_inherit
)
155 os
<< lcolor
.getGUIName(f
.color()) << ", ";
156 // FIXME: uncomment this when we support background.
157 //if (f.background() != Color_inherit)
158 // os << lcolor.getGUIName(f.background()) << ", ";
159 if (f
.emph() != FONT_INHERIT
)
160 os
<< bformat(_("Emphasis %1$s, "),
161 _(GUIMiscNames
[f
.emph()]));
162 if (f
.underbar() != FONT_INHERIT
)
163 os
<< bformat(_("Underline %1$s, "),
164 _(GUIMiscNames
[f
.underbar()]));
165 if (f
.strikeout() != FONT_INHERIT
)
166 os
<< bformat(_("Strikeout %1$s, "),
167 _(GUIMiscNames
[f
.strikeout()]));
168 if (f
.uuline() != FONT_INHERIT
)
169 os
<< bformat(_("Double underline %1$s, "),
170 _(GUIMiscNames
[f
.uuline()]));
171 if (f
.uwave() != FONT_INHERIT
)
172 os
<< bformat(_("Wavy underline %1$s, "),
173 _(GUIMiscNames
[f
.uwave()]));
174 if (f
.noun() != FONT_INHERIT
)
175 os
<< bformat(_("Noun %1$s, "),
176 _(GUIMiscNames
[f
.noun()]));
177 if (f
== inherit_font
)
178 os
<< _("Default") << ", ";
184 docstring
const Font::stateText(BufferParams
* params
) const
187 os
<< lyx::stateText(bits_
);
188 if (!params
|| (language() != params
->language
))
189 os
<< bformat(_("Language: %1$s, "),
190 _(language()->display()));
191 if (bits_
.number() != FONT_OFF
)
192 os
<< bformat(_(" Number %1$s"),
193 _(GUIMiscNames
[bits_
.number()]));
194 return rtrim(os
.str(), ", ");
198 // Returns size in latex format
199 string
const Font::latexSize() const
201 return LaTeXSizeNames
[bits_
.size()];
205 /// Writes the changes from this font to orgfont in .lyx format in file
206 void Font::lyxWriteChanges(Font
const & orgfont
,
210 if (orgfont
.fontInfo().family() != bits_
.family())
211 os
<< "\\family " << LyXFamilyNames
[bits_
.family()] << "\n";
212 if (orgfont
.fontInfo().series() != bits_
.series())
213 os
<< "\\series " << LyXSeriesNames
[bits_
.series()] << "\n";
214 if (orgfont
.fontInfo().shape() != bits_
.shape())
215 os
<< "\\shape " << LyXShapeNames
[bits_
.shape()] << "\n";
216 if (orgfont
.fontInfo().size() != bits_
.size())
217 os
<< "\\size " << LyXSizeNames
[bits_
.size()] << "\n";
218 if (orgfont
.fontInfo().emph() != bits_
.emph())
219 os
<< "\\emph " << LyXMiscNames
[bits_
.emph()] << "\n";
220 if (orgfont
.fontInfo().number() != bits_
.number())
221 os
<< "\\numeric " << LyXMiscNames
[bits_
.number()] << "\n";
222 if (orgfont
.fontInfo().underbar() != bits_
.underbar()) {
223 // This is only for backwards compatibility
224 switch (bits_
.underbar()) {
225 case FONT_OFF
: os
<< "\\bar no\n"; break;
226 case FONT_ON
: os
<< "\\bar under\n"; break;
227 case FONT_TOGGLE
: lyxerr
<< "Font::lyxWriteFontChanges: "
228 "FONT_TOGGLE should not appear here!"
231 case FONT_INHERIT
: os
<< "\\bar default\n"; break;
232 case FONT_IGNORE
: lyxerr
<< "Font::lyxWriteFontChanges: "
233 "IGNORE should not appear here!"
238 if (orgfont
.fontInfo().strikeout() != bits_
.strikeout()) {
239 os
<< "\\strikeout " << LyXMiscNames
[bits_
.strikeout()] << "\n";
241 if (orgfont
.fontInfo().uuline() != bits_
.uuline()) {
242 os
<< "\\uuline " << LyXMiscNames
[bits_
.uuline()] << "\n";
244 if (orgfont
.fontInfo().uwave() != bits_
.uwave()) {
245 os
<< "\\uwave " << LyXMiscNames
[bits_
.uwave()] << "\n";
247 if (orgfont
.fontInfo().noun() != bits_
.noun()) {
248 os
<< "\\noun " << LyXMiscNames
[bits_
.noun()] << "\n";
250 if (orgfont
.fontInfo().color() != bits_
.color())
251 os
<< "\\color " << lcolor
.getLyXName(bits_
.color()) << '\n';
252 // FIXME: uncomment this when we support background.
253 //if (orgfont.fontInfo().background() != bits_.background())
254 // os << "\\color " << lcolor.getLyXName(bits_.background()) << '\n';
255 if (orgfont
.language() != language() &&
256 language() != latex_language
) {
258 os
<< "\\lang " << language()->lang() << "\n";
260 os
<< "\\lang unknown\n";
265 /// Writes the head of the LaTeX needed to impose this font
266 // Returns number of chars written.
267 int Font::latexWriteStartChanges(odocstream
& os
, BufferParams
const & bparams
,
268 OutputParams
const & runparams
,
270 Font
const & prev
) const
275 if (language()->babel() != base
.language()->babel() &&
276 language() != prev
.language()) {
277 if (language()->lang() == "farsi") {
280 } else if (!isRightToLeft() &&
281 base
.language()->lang() == "farsi") {
284 } else if (language()->lang() == "arabic_arabi") {
287 } else if (!isRightToLeft() &&
288 base
.language()->lang() == "arabic_arabi") {
291 // currently the remaining RTL languages are arabic_arabtex and hebrew
292 } else if (isRightToLeft() != prev
.isRightToLeft()) {
293 if (isRightToLeft()) {
300 } else if (!language()->babel().empty()) {
302 subst(lyxrc
.language_command_local
,
303 "$$lang", language()->babel());
304 os
<< from_ascii(tmp
);
305 count
+= tmp
.length();
312 if (language()->encoding()->package() == Encoding::CJK
) {
313 pair
<bool, int> const c
= switchEncoding(os
, bparams
,
314 runparams
, *(language()->encoding()));
316 open_encoding_
= true;
318 runparams
.encoding
= language()->encoding();
322 // When the current language is Hebrew, Arabic, or Farsi
323 // the numbers are written Left-to-Right. ArabTeX package
324 // reorders the number automatically but the packages used
325 // for Hebrew and Farsi (Arabi) do not.
326 if (bits_
.number() == FONT_ON
&& prev
.fontInfo().number() != FONT_ON
327 && (language()->lang() == "hebrew"
328 || language()->lang() == "farsi"
329 || language()->lang() == "arabic_arabi")) {
335 f
.reduce(base
.bits_
);
337 if (f
.family() != INHERIT_FAMILY
) {
339 << LaTeXFamilyNames
[f
.family()]
341 count
+= strlen(LaTeXFamilyNames
[f
.family()]) + 2;
342 env
= true; //We have opened a new environment
344 if (f
.series() != INHERIT_SERIES
) {
346 << LaTeXSeriesNames
[f
.series()]
348 count
+= strlen(LaTeXSeriesNames
[f
.series()]) + 2;
349 env
= true; //We have opened a new environment
351 if (f
.shape() != INHERIT_SHAPE
) {
353 << LaTeXShapeNames
[f
.shape()]
355 count
+= strlen(LaTeXShapeNames
[f
.shape()]) + 2;
356 env
= true; //We have opened a new environment
358 if (f
.color() != Color_inherit
&& f
.color() != Color_ignore
) {
360 << from_ascii(lcolor
.getLaTeXName(f
.color()))
362 count
+= lcolor
.getLaTeXName(f
.color()).length() + 13;
363 env
= true; //We have opened a new environment
365 // FIXME: uncomment this when we support background.
367 if (f.background() != Color_inherit && f.background() != Color_ignore) {
369 << from_ascii(lcolor.getLaTeXName(f.background()))
371 count += lcolor.getLaTeXName(f.background()).length() + 13;
372 env = true; //We have opened a new environment
375 if (f
.emph() == FONT_ON
) {
378 env
= true; //We have opened a new environment
380 if (f
.underbar() == FONT_ON
) {
383 runparams
.inulemcmd
= true;
384 env
= true; //We have opened a new environment
386 if (f
.strikeout() == FONT_ON
) {
389 runparams
.inulemcmd
= true;
390 env
= true; //We have opened a new environment
392 if (f
.uuline() == FONT_ON
) {
395 runparams
.inulemcmd
= true;
396 env
= true; //We have opened a new environment
398 if (f
.uwave() == FONT_ON
) {
401 runparams
.inulemcmd
= true;
402 env
= true; //We have opened a new environment
404 // \noun{} is a LyX special macro
405 if (f
.noun() == FONT_ON
) {
408 env
= true; //We have opened a new environment
410 if (f
.size() != FONT_SIZE_INHERIT
) {
411 // If we didn't open an environment above, we open one here
417 << LaTeXSizeNames
[f
.size()]
419 count
+= strlen(LaTeXSizeNames
[f
.size()]) + 2;
425 /// Writes ending block of LaTeX needed to close use of this font
426 // Returns number of chars written
427 // This one corresponds to latexWriteStartChanges(). (Asger)
428 int Font::latexWriteEndChanges(odocstream
& os
, BufferParams
const & bparams
,
429 OutputParams
const & runparams
,
432 bool const & closeLanguage
) const
437 // reduce the current font to changes against the base
438 // font (of the layout). We use a temporary for this to
439 // avoid changing this font instance, as that would break
441 f
.reduce(base
.bits_
);
443 if (f
.family() != INHERIT_FAMILY
) {
446 env
= true; // Size change need not bother about closing env.
448 if (f
.series() != INHERIT_SERIES
) {
451 env
= true; // Size change need not bother about closing env.
453 if (f
.shape() != INHERIT_SHAPE
) {
456 env
= true; // Size change need not bother about closing env.
458 if (f
.color() != Color_inherit
&& f
.color() != Color_ignore
) {
461 env
= true; // Size change need not bother about closing env.
463 if (f
.emph() == FONT_ON
) {
466 env
= true; // Size change need not bother about closing env.
468 if (f
.underbar() == FONT_ON
) {
471 runparams
.inulemcmd
= false;
472 env
= true; // Size change need not bother about closing env.
474 if (f
.strikeout() == FONT_ON
) {
477 runparams
.inulemcmd
= false;
478 env
= true; // Size change need not bother about closing env.
480 if (f
.uuline() == FONT_ON
) {
483 runparams
.inulemcmd
= false;
484 env
= true; // Size change need not bother about closing env.
486 if (f
.uwave() == FONT_ON
) {
489 runparams
.inulemcmd
= false;
490 env
= true; // Size change need not bother about closing env.
492 if (f
.noun() == FONT_ON
) {
495 env
= true; // Size change need not bother about closing env.
497 if (f
.size() != FONT_SIZE_INHERIT
) {
498 // We only have to close if only size changed
505 // When the current language is Hebrew, Arabic, or Farsi
506 // the numbers are written Left-to-Right. ArabTeX package
507 // reorders the number automatically but the packages used
508 // for Hebrew and Farsi (Arabi) do not.
509 if (bits_
.number() == FONT_ON
&& next
.fontInfo().number() != FONT_ON
510 && (language()->lang() == "hebrew"
511 || language()->lang() == "farsi"
512 || language()->lang() == "arabic_arabi")) {
517 if (open_encoding_
) {
518 // We need to close the encoding even if it does not change
519 // to do correct environment nesting
520 Encoding
const * const ascii
= encodings
.fromLyXName("ascii");
521 pair
<bool, int> const c
= switchEncoding(os
, bparams
,
523 LASSERT(c
.first
, /**/);
525 runparams
.encoding
= ascii
;
526 open_encoding_
= false;
530 language() != base
.language() && language() != next
.language()) {
539 string
Font::toString(bool const toggle
) const
541 string
const lang
= (language() == reset_language
)
542 ? "reset" : language()->lang();
545 os
<< "family " << bits_
.family() << '\n'
546 << "series " << bits_
.series() << '\n'
547 << "shape " << bits_
.shape() << '\n'
548 << "size " << bits_
.size() << '\n'
549 << "emph " << bits_
.emph() << '\n'
550 << "underbar " << bits_
.underbar() << '\n'
551 << "strikeout " << bits_
.strikeout() << '\n'
552 << "uuline " << bits_
.uuline() << '\n'
553 << "uwave " << bits_
.uwave() << '\n'
554 << "noun " << bits_
.noun() << '\n'
555 << "number " << bits_
.number() << '\n'
556 << "color " << bits_
.color() << '\n'
557 << "language " << lang
<< '\n'
558 << "toggleall " << convert
<string
>(toggle
);
563 bool Font::fromString(string
const & data
, bool & toggle
)
565 istringstream
is(data
);
573 token
= lex
.getString();
575 if (token
.empty() || !lex
.next())
578 if (token
== "family") {
579 int const next
= lex
.getInteger();
580 bits_
.setFamily(FontFamily(next
));
582 } else if (token
== "series") {
583 int const next
= lex
.getInteger();
584 bits_
.setSeries(FontSeries(next
));
586 } else if (token
== "shape") {
587 int const next
= lex
.getInteger();
588 bits_
.setShape(FontShape(next
));
590 } else if (token
== "size") {
591 int const next
= lex
.getInteger();
592 bits_
.setSize(FontSize(next
));
594 } else if (token
== "emph" || token
== "underbar" ||
595 token
== "noun" || token
== "number" ||
596 token
== "uuline" || token
== "uwave" ||
597 token
== "strikeout") {
599 int const next
= lex
.getInteger();
600 FontState
const misc
= FontState(next
);
604 else if (token
== "underbar")
605 bits_
.setUnderbar(misc
);
606 else if (token
== "strikeout")
607 bits_
.setStrikeout(misc
);
608 else if (token
== "uuline")
609 bits_
.setUuline(misc
);
610 else if (token
== "uwave")
611 bits_
.setUwave(misc
);
612 else if (token
== "noun")
614 else if (token
== "number")
615 bits_
.setNumber(misc
);
617 } else if (token
== "color") {
618 int const next
= lex
.getInteger();
619 bits_
.setColor(ColorCode(next
));
622 } else if (token == "background") {
623 int const next = lex.getInteger();
624 bits_.setBackground(ColorCode(next));
627 } else if (token
== "language") {
628 string
const next
= lex
.getString();
629 setLanguage(languages
.getLanguage(next
));
631 } else if (token
== "toggleall") {
632 toggle
= lex
.getBool();
635 // Unrecognised token
645 void Font::validate(LaTeXFeatures
& features
) const
647 BufferParams
const & bparams
= features
.bufferParams();
648 Language
const * doc_language
= bparams
.language
;
650 if (bits_
.noun() == FONT_ON
) {
651 LYXERR(Debug::LATEX
, "font.noun: " << bits_
.noun());
652 features
.require("noun");
653 LYXERR(Debug::LATEX
, "Noun enabled. Font: " << to_utf8(stateText(0)));
655 if (bits_
.underbar() == FONT_ON
) {
656 LYXERR(Debug::LATEX
, "font.underline: " << bits_
.underbar());
657 features
.require("ulem");
658 LYXERR(Debug::LATEX
, "Underline enabled. Font: " << to_utf8(stateText(0)));
660 if (bits_
.strikeout() == FONT_ON
) {
661 LYXERR(Debug::LATEX
, "font.strikeout: " << bits_
.strikeout());
662 features
.require("ulem");
663 LYXERR(Debug::LATEX
, "Strikeout enabled. Font: " << to_utf8(stateText(0)));
665 if (bits_
.uuline() == FONT_ON
) {
666 LYXERR(Debug::LATEX
, "font.uuline: " << bits_
.uuline());
667 features
.require("ulem");
668 LYXERR(Debug::LATEX
, "Double underline enabled. Font: " << to_utf8(stateText(0)));
670 if (bits_
.uwave() == FONT_ON
) {
671 LYXERR(Debug::LATEX
, "font.uwave: " << bits_
.uwave());
672 features
.require("ulem");
673 LYXERR(Debug::LATEX
, "Wavy underline enabled. Font: " << to_utf8(stateText(0)));
675 switch (bits_
.color()) {
679 // probably we should put here all interface colors used for
680 // font displaying! For now I just add this ones I know of (Jug)
682 case Color_notelabel
:
685 features
.require("color");
686 LYXERR(Debug::LATEX
, "Color enabled. Font: " << to_utf8(stateText(0)));
689 // FIXME: Do something for background and soul package?
691 if (lang_
->babel() != doc_language
->babel() &&
692 lang_
!= ignore_language
&&
693 lang_
!= latex_language
)
695 features
.useLanguage(lang_
);
696 LYXERR(Debug::LATEX
, "Found language " << lang_
->lang());
701 ostream
& operator<<(ostream
& os
, FontState fms
)
703 return os
<< int(fms
);
707 ostream
& operator<<(ostream
& os
, FontInfo
const & f
)
710 << " family " << f
.family()
711 << " series " << f
.series()
712 << " shape " << f
.shape()
713 << " size " << f
.size()
714 << " color " << f
.color()
715 // FIXME: uncomment this when we support background.
716 //<< " background " << f.background()
717 << " emph " << f
.emph()
718 << " underbar " << f
.underbar()
719 << " strikeout " << f
.strikeout()
720 << " uuline " << f
.uuline()
721 << " uwave " << f
.uwave()
722 << " noun " << f
.noun()
723 << " number " << f
.number();
727 ostream
& operator<<(ostream
& os
, Font
const & font
)
729 return os
<< font
.bits_
730 << " lang: " << (font
.lang_
? font
.lang_
->lang() : 0);