]> git.lyx.org Git - features.git/blob - src/FontList.cpp
Introducing FontList::validate()
[features.git] / src / FontList.cpp
1 /**
2  * \file FontList.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Asger Alstrup
7  * \author Lars Gullik Bjønnes
8  * \author Jean-Marc Lasgouttes
9  * \author Angus Leeming
10  * \author John Levon
11  * \author André Pönitz
12  * \author Dekel Tsur
13  * \author Jürgen Vigna
14  * \author Abdelrazak Younes
15  *
16  * Full author contact details are available in file CREDITS.
17  */
18
19 #include <config.h>
20
21 #include "FontList.h"
22
23 #include "BufferParams.h"
24 #include "debug.h"
25 #include "Language.h"
26 #include "LaTeXFeatures.h"
27
28 #include <boost/next_prior.hpp>
29
30 #include <algorithm>
31
32 using std::distance;
33 using std::endl;
34 using std::string;
35 using std::ostream;
36
37 namespace lyx {
38
39 namespace {
40
41 class matchFT
42 {
43 public:
44         /// used by lower_bound and upper_bound
45         int operator()(FontTable const & a, FontTable const & b) const {
46                 return a.pos() < b.pos();
47         }
48 };
49
50 } // anon namespace
51
52 FontList::iterator FontList::fontIterator(pos_type pos)
53 {
54         static Font dummy;
55         FontTable search_elem(pos, dummy);
56         return lower_bound(list_.begin(), list_.end(), search_elem,
57                 matchFT());
58 }
59
60
61 FontList::const_iterator FontList::fontIterator(pos_type pos) const
62 {
63         static Font dummy;
64         FontTable search_elem(pos, dummy);
65         return lower_bound(list_.begin(), list_.end(), search_elem,
66                 matchFT());
67 }
68
69
70 Font & FontList::get(pos_type pos)
71 {
72         iterator end = list_.end();
73         iterator it = fontIterator(pos);
74         if (it != end && it->pos() == pos)
75                 return it->font_;
76         static Font dummy;
77         return dummy;
78 }
79
80
81 void FontList::erase(pos_type pos)
82 {
83         // Erase entries in the tables.
84         iterator it = fontIterator(pos);
85         iterator beg = list_.begin();
86         if (it != list_.end() && it->pos() == pos
87                 && (pos == 0 
88                         || (it != beg && boost::prior(it)->pos() == pos - 1))) {
89
90                 // If it is a multi-character font
91                 // entry, we just make it smaller
92                 // (see update below), otherwise we
93                 // should delete it.
94                 unsigned int const i = it - beg;
95                 list_.erase(beg + i);
96                 it = beg + i;
97                 if (i > 0 && i < list_.size() &&
98                     list_[i - 1].font() == list_[i].font()) {
99                         list_.erase(beg + i - 1);
100                         it = beg + i - 1;
101                 }
102         }
103
104         // Update all other entries
105         iterator end = list_.end();
106         for (; it != end; ++it)
107                 it->pos(it->pos() - 1);
108 }
109
110 void FontList::increasePosAfterPos(pos_type pos)
111 {
112         List::iterator end = list_.end();
113         List::iterator it = fontIterator(pos);
114         for (; it != end; ++it)
115                 ++it->pos_;
116 }
117
118
119 void FontList::decreasePosAfterPos(pos_type pos)
120 {
121         List::iterator end = list_.end();
122         List::iterator it = fontIterator(pos);
123         for (; it != end; ++it)
124                 --it->pos_;
125 }
126
127
128 void FontList::set(pos_type pos, Font const & font)
129 {
130         // No need to simplify this because it will disappear
131         // in a new kernel. (Asger)
132         // Next search font table
133
134         iterator beg = list_.begin();
135         iterator it = beg;
136         iterator endit = list_.end();
137         for (; it != endit; ++it) {
138                 if (it->pos() >= pos)
139                         break;
140         }
141         size_t const i = distance(beg, it);
142         bool notfound = (it == endit);
143
144         if (!notfound && list_[i].font() == font)
145                 return;
146
147         bool begin = pos == 0 || notfound ||
148                 (i > 0 && list_[i - 1].pos() == pos - 1);
149         // Is position pos is a beginning of a font block?
150         bool end = !notfound && list_[i].pos() == pos;
151         // Is position pos is the end of a font block?
152         if (begin && end) { // A single char block
153                 if (i + 1 < list_.size() &&
154                     list_[i + 1].font() == font) {
155                         // Merge the singleton block with the next block
156                         list_.erase(list_.begin() + i);
157                         if (i > 0 && list_[i - 1].font() == font)
158                                 list_.erase(list_.begin() + i - 1);
159                 } else if (i > 0 && list_[i - 1].font() == font) {
160                         // Merge the singleton block with the previous block
161                         list_[i - 1].pos(pos);
162                         list_.erase(list_.begin() + i);
163                 } else
164                         list_[i].font(font);
165         } else if (begin) {
166                 if (i > 0 && list_[i - 1].font() == font)
167                         list_[i - 1].pos(pos);
168                 else
169                         list_.insert(list_.begin() + i,
170                                         FontTable(pos, font));
171         } else if (end) {
172                 list_[i].pos(pos - 1);
173                 if (!(i + 1 < list_.size() &&
174                       list_[i + 1].font() == font))
175                         list_.insert(list_.begin() + i + 1,
176                                         FontTable(pos, font));
177         } else { // The general case. The block is splitted into 3 blocks
178                 list_.insert(list_.begin() + i,
179                                 FontTable(pos - 1, list_[i].font()));
180                 list_.insert(list_.begin() + i + 1,
181                                 FontTable(pos, font));
182         }
183 }
184
185
186 Font_size FontList::highestInRange
187         (pos_type startpos, pos_type endpos, Font_size def_size) const
188 {
189         if (list_.empty())
190                 return def_size;
191
192         const_iterator end_it = list_.begin();
193         const_iterator const end = list_.end();
194         for (; end_it != end; ++end_it) {
195                 if (end_it->pos() >= endpos)
196                         break;
197         }
198
199         if (end_it != end)
200                 ++end_it;
201
202         FontList::const_iterator cit = list_.begin();
203         for (; cit != end; ++cit) {
204                 if (cit->pos() >= startpos)
205                         break;
206         }
207
208         Font::FONT_SIZE maxsize = Font::SIZE_TINY;
209         for (; cit != end_it; ++cit) {
210                 Font::FONT_SIZE size = cit->font().size();
211                 if (size == Font::INHERIT_SIZE)
212                         size = def_size;
213                 if (size > maxsize && size <= Font::SIZE_HUGER)
214                         maxsize = size;
215         }
216         return maxsize;
217 }
218
219
220 bool FontList::hasChangeInRange(pos_type pos, int len) const
221 {
222         // FIXME: can't we use fontIterator(pos) instead?
223         const_iterator cit = list_.begin();
224         const_iterator end = list_.end();
225         for (; cit != end; ++cit) {
226                 if (cit->pos() >= pos)
227                         break;
228         }
229         if (cit != end && pos + len - 1 > cit->pos())
230                 return false;
231
232         return true;
233 }
234
235
236 void FontList::validate(LaTeXFeatures & features) const
237 {
238         BufferParams const & bparams = features.bufferParams();
239         Language const * doc_language = bparams.language;
240
241         const_iterator fcit = list_.begin();
242         const_iterator fend = list_.end();
243         for (; fcit != fend; ++fcit) {
244                 if (fcit->font().noun() == Font::ON) {
245                         LYXERR(Debug::LATEX) << "font.noun: "
246                                              << fcit->font().noun()
247                                              << endl;
248                         features.require("noun");
249                         LYXERR(Debug::LATEX) << "Noun enabled. Font: "
250                                              << to_utf8(fcit->font().stateText(0))
251                                              << endl;
252                 }
253                 switch (fcit->font().color()) {
254                 case Color::none:
255                 case Color::inherit:
256                 case Color::ignore:
257                         // probably we should put here all interface colors used for
258                         // font displaying! For now I just add this ones I know of (Jug)
259                 case Color::latex:
260                 case Color::note:
261                         break;
262                 default:
263                         features.require("color");
264                         LYXERR(Debug::LATEX) << "Color enabled. Font: "
265                                              << to_utf8(fcit->font().stateText(0))
266                                              << endl;
267                 }
268
269                 Language const * language = fcit->font().language();
270                 if (language->babel() != doc_language->babel() &&
271                     language != ignore_language &&
272                     language != latex_language)
273                 {
274                         features.useLanguage(language);
275                         LYXERR(Debug::LATEX) << "Found language "
276                                              << language->lang() << endl;
277                 }
278         }
279 }
280
281 } // namespace lyx