]> git.lyx.org Git - lyx.git/blob - src/FontList.cpp
a5ffca8102949a5665a0c153a0942418729b8557
[lyx.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 <boost/next_prior.hpp>
24
25 #include <algorithm>
26
27 using std::distance;
28
29 namespace lyx {
30
31 namespace {
32
33 class matchFT
34 {
35 public:
36         /// used by lower_bound and upper_bound
37         int operator()(FontTable const & a, FontTable const & b) const {
38                 return a.pos() < b.pos();
39         }
40 };
41
42 } // anon namespace
43
44 FontList::iterator FontList::fontIterator(pos_type pos)
45 {
46         static Font dummy;
47         FontTable search_elem(pos, dummy);
48         return lower_bound(list_.begin(), list_.end(), search_elem,
49                 matchFT());
50 }
51
52
53 FontList::const_iterator FontList::fontIterator(pos_type pos) const
54 {
55         static Font dummy;
56         FontTable search_elem(pos, dummy);
57         return lower_bound(list_.begin(), list_.end(), search_elem,
58                 matchFT());
59 }
60
61
62 Font & FontList::get(pos_type pos)
63 {
64         iterator end = list_.end();
65         iterator it = fontIterator(pos);
66         if (it != end && it->pos() == pos)
67                 return it->font_;
68         static Font dummy;
69         return dummy;
70 }
71
72
73 void FontList::erase(pos_type pos)
74 {
75         // Erase entries in the tables.
76         iterator it = fontIterator(pos);
77         iterator beg = list_.begin();
78         if (it != list_.end() && it->pos() == pos
79                 && (pos == 0 
80                         || (it != list_.begin() && boost::prior(it)->pos() == pos - 1))) {
81
82                 // If it is a multi-character font
83                 // entry, we just make it smaller
84                 // (see update below), otherwise we
85                 // should delete it.
86                 unsigned int const i = it - list_.begin();
87                 list_.erase(it);
88                 if (i >= list_.size())
89                         return;
90                 it = list_.begin() + i;
91                 if (i > 0 && i < list_.size() &&
92                     list_[i - 1].font() == list_[i].font()) {
93                         list_.erase(beg + i - 1);
94                         it = list_.begin() + i - 1;
95                 }
96         }
97
98         // Update all other entries
99         iterator end = list_.end();
100         for (; it != end; ++it)
101                 it->pos(it->pos() - 1);
102 }
103
104 void FontList::increasePosAfterPos(pos_type pos)
105 {
106         List::iterator end = list_.end();
107         List::iterator it = fontIterator(pos);
108         for (; it != end; ++it)
109                 ++it->pos_;
110 }
111
112
113 void FontList::decreasePosAfterPos(pos_type pos)
114 {
115         List::iterator end = list_.end();
116         List::iterator it = fontIterator(pos);
117         for (; it != end; ++it)
118                 --it->pos_;
119 }
120
121
122 void FontList::setRange(pos_type startpos, pos_type endpos, Font const & font)
123 {
124         // FIXME: Optimize!!!
125         for (pos_type pos = startpos; pos != endpos; ++pos)
126                 set(pos, font);
127 }
128
129
130 void FontList::set(pos_type pos, Font const & font)
131 {
132         // No need to simplify this because it will disappear
133         // in a new kernel. (Asger)
134         // Next search font table
135
136         iterator beg = list_.begin();
137         iterator it = beg;
138         iterator endit = list_.end();
139         bool found = false;
140         for (; it != endit; ++it) {
141                 if (it->pos() >= pos) {
142                         found = true;
143                         break;
144                 }
145         }
146         if (found && it->font() == font)
147                 return;
148
149         size_t const i = distance(beg, it);
150
151         // Is position pos is a beginning of a font block?
152         bool begin = pos == 0 || !found 
153                 || (i > 0 && list_[i - 1].pos() == pos - 1);
154
155         // Is position pos is the end of a font block?
156         bool end = found && list_[i].pos() == pos;
157
158         if (!begin && !end) {
159                 // The general case: The block is splitted into 3 blocks
160                 list_.insert(list_.begin() + i,
161                                 FontTable(pos - 1, list_[i].font()));
162                 list_.insert(list_.begin() + i + 1,
163                                 FontTable(pos, font));
164                 return;
165         }
166
167         if (begin && end) {
168                 // A single char block
169                 if (i + 1 < list_.size() &&
170                     list_[i + 1].font() == font) {
171                         // Merge the singleton block with the next block
172                         list_.erase(list_.begin() + i);
173                         if (i > 0 && list_[i - 1].font() == font)
174                                 list_.erase(list_.begin() + i - 1);
175                 } else if (i > 0 && list_[i - 1].font() == font) {
176                         // Merge the singleton block with the previous block
177                         list_[i - 1].pos(pos);
178                         list_.erase(list_.begin() + i);
179                 } else
180                         list_[i].font(font);
181         } else if (begin) {
182                 if (i > 0 && list_[i - 1].font() == font)
183                         list_[i - 1].pos(pos);
184                 else
185                         list_.insert(list_.begin() + i,
186                                         FontTable(pos, font));
187         } else if (end) {
188                 list_[i].pos(pos - 1);
189                 if (!(i + 1 < list_.size() &&
190                       list_[i + 1].font() == font))
191                         list_.insert(list_.begin() + i + 1,
192                                         FontTable(pos, font));
193         }
194 }
195
196
197 FontSize FontList::highestInRange
198         (pos_type startpos, pos_type endpos, FontSize def_size) const
199 {
200         if (list_.empty())
201                 return def_size;
202
203         const_iterator end_it = list_.begin();
204         const_iterator const end = list_.end();
205         for (; end_it != end; ++end_it) {
206                 if (end_it->pos() >= endpos)
207                         break;
208         }
209
210         if (end_it != end)
211                 ++end_it;
212
213         FontList::const_iterator cit = list_.begin();
214         for (; cit != end; ++cit) {
215                 if (cit->pos() >= startpos)
216                         break;
217         }
218
219         FontSize maxsize = FONT_SIZE_TINY;
220         for (; cit != end_it; ++cit) {
221                 FontSize size = cit->font().fontInfo().size();
222                 if (size == FONT_SIZE_INHERIT)
223                         size = def_size;
224                 if (size > maxsize && size <= FONT_SIZE_HUGER)
225                         maxsize = size;
226         }
227         return maxsize;
228 }
229
230
231 bool FontList::hasChangeInRange(pos_type pos, int len) const
232 {
233         // FIXME: can't we use fontIterator(pos) instead?
234         const_iterator cit = list_.begin();
235         const_iterator end = list_.end();
236         for (; cit != end; ++cit) {
237                 if (cit->pos() >= pos)
238                         break;
239         }
240         if (cit != end && pos + len - 1 > cit->pos())
241                 return false;
242
243         return true;
244 }
245
246
247 void FontList::validate(LaTeXFeatures & features) const
248 {
249         const_iterator fcit = list_.begin();
250         const_iterator fend = list_.end();
251         for (; fcit != fend; ++fcit)
252                 fcit->font().validate(features);
253 }
254
255 } // namespace lyx