]> git.lyx.org Git - lyx.git/blob - src/frontends/qt4/GuiFontMetrics.C
165c6459f2cac6128f4bdc70d32a674e7585c4e2
[lyx.git] / src / frontends / qt4 / GuiFontMetrics.C
1 /**
2  * \file GuiFontMetrics.C
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author unknown
7  * \author John Levon
8  *
9  * Full author contact details are available in file CREDITS.
10  */
11
12 #include <config.h>
13
14 #include "GuiFontMetrics.h"
15
16 #include "qt_helpers.h"
17
18 #include "language.h"
19
20 #include "support/unicode.h"
21
22 using std::string;
23
24 namespace lyx {
25 namespace frontend {
26
27 namespace {
28 // Used for checking initialisation state of the C-ish metrics table.
29 const short int BadMetrics = -1000;
30 }
31
32
33 GuiFontMetrics::GuiFontMetrics(QFont const & font)
34 : metrics_(font), smallcaps_metrics_(font), smallcaps_shape_(false)
35 {
36 #ifdef USE_LYX_FONTCACHE
37  for (size_t i = 0; i != MaxCharType; ++i) {
38          metrics_cache_[i].width = BadMetrics;
39          metrics_cache_[i].ascent = BadMetrics;
40          metrics_cache_[i].descent = BadMetrics;
41  }
42 #endif
43 }
44
45
46 GuiFontMetrics::GuiFontMetrics(QFont const & font, QFont const & smallcaps_font)
47 : metrics_(font), smallcaps_metrics_(smallcaps_font), smallcaps_shape_(true)
48 {
49 }
50
51
52 int GuiFontMetrics::maxAscent() const
53 {
54         return metrics_.ascent();
55 }
56
57
58 int GuiFontMetrics::maxDescent() const
59 {
60         // We add 1 as the value returned by QT is different than X
61         // See http://doc.trolltech.com/2.3/qfontmetrics.html#200b74
62         return metrics_.descent() + 1;
63 }
64
65
66 int GuiFontMetrics::lbearing(char_type c) const
67 {
68         return metrics_.leftBearing(ucs4_to_qchar(c));
69 }
70
71
72 int GuiFontMetrics::rbearing(char_type c) const
73 {
74         // Qt rbearing is from the right edge of the char's width().
75         QChar sc = ucs4_to_qchar(c);
76         return metrics_.width(sc) - metrics_.rightBearing(sc);
77 }
78
79
80 int GuiFontMetrics::smallcapsWidth(QString const & s) const
81 {
82         int w = 0;
83         int const ls = s.size();
84
85         for (int i = 0; i < ls; ++i) {
86                 QChar const & c = s[i];
87                 QChar const uc = c.toUpper();
88                 if (c != uc)
89                         w += smallcaps_metrics_.width(uc);
90                 else
91                         w += metrics_.width(c);
92         }
93         return w;
94 }
95
96
97 int GuiFontMetrics::width(char_type const * s, size_t ls) const
98 {
99         // Caution: The following ucs4_to_something conversions work for
100         // symbol fonts only because they are no real conversions but simple
101         // casts in reality.
102
103         if (ls == 1 && !smallcaps_shape_) {
104                 return width(s[0]);
105         }
106
107         if (smallcaps_shape_) {
108                 QString ucs2;
109                 ucs4_to_qstring(s, ls, ucs2);
110                 return smallcapsWidth(ucs2);
111         }
112
113         int w = 0;
114         for (unsigned int i = 0; i < ls; ++i)
115                 w += width(s[i]);
116
117         return w;
118 }
119
120
121 int GuiFontMetrics::width(QString const & ucs2) const
122 {
123         int const ls = ucs2.size();
124         if (ls == 1 && !smallcaps_shape_) {
125                 return width(ucs2[0].unicode());
126         }
127
128         if (smallcaps_shape_)
129                 return smallcapsWidth(ucs2);
130
131         int w = 0;
132         for (int i = 0; i < ls; ++i)
133                 w += width(ucs2[i].unicode());
134
135         return w;
136 }
137
138
139 int GuiFontMetrics::signedWidth(docstring const & s) const
140 {
141         if (s.empty())
142                 return 0;
143
144         if (s[0] == '-')
145                 return -width(&(s[1]), s.length() - 1);
146         else
147                 return FontMetrics::width(s);
148 }
149
150
151 void GuiFontMetrics::rectText(docstring const & str,
152         int & w, int & ascent, int & descent) const
153 {
154         static int const d = 2;
155         w = FontMetrics::width(str) + d * 2 + 2;
156         ascent = metrics_.ascent() + d;
157         descent = metrics_.descent() + d;
158 }
159
160
161
162 void GuiFontMetrics::buttonText(docstring const & str,
163         int & w, int & ascent, int & descent) const
164 {
165         static int const d = 3;
166         w = FontMetrics::width(str) + d * 2 + 2;
167         ascent = metrics_.ascent() + d;
168         descent = metrics_.descent() + d;
169 }
170
171 #ifndef USE_LYX_FONTCACHE
172
173 int GuiFontMetrics::ascent(char_type c) const
174 {
175         QRect const & r = metrics_.boundingRect(ucs4_to_qchar(c));
176         return -r.top();
177 }
178
179
180 int GuiFontMetrics::descent(char_type c) const
181 {
182         QRect const & r = metrics_.boundingRect(ucs4_to_qchar(c));
183         return r.bottom() + 1;
184 }
185
186 #else
187
188 void GuiFontMetrics::fillCache(unsigned short val) const
189 {
190         QRect const & r = metrics_.boundingRect(QChar(val));
191         metrics_cache_[val].descent = static_cast<short>(r.bottom() + 1);
192         metrics_cache_[val].ascent = static_cast<short>(-r.top());
193         // We could as well compute the width but this is not really
194         // needed for now as it is done directly in width() below.
195         //metrics_cache_[val].width = metrics_.width(QChar(val));
196 }
197
198
199 int GuiFontMetrics::width(char_type c) const
200 {
201         // FIXME: The following cast is not a real conversion but it work
202         // for the ucs2 subrange of unicode. Instead of an assertion we should
203         // give the metrics of some special characters that indicates that
204         // its display is not supported.
205         BOOST_ASSERT(c < MaxCharType);
206         unsigned short val = static_cast<unsigned short>(c);
207         if (metrics_cache_[val].width == BadMetrics) {
208                 metrics_cache_[val].width 
209                         = static_cast<short>(metrics_.width(QChar(val)));
210         }
211
212         return metrics_cache_[val].width;
213 }
214
215
216 int GuiFontMetrics::ascent(char_type c) const
217 {
218         // FIXME: The following cast is not a real conversion but it work
219         // for the ucs2 subrange of unicode. Instead of an assertion we should
220         // give the metrics of some special characters that indicates that
221         // its display is not supported.
222         BOOST_ASSERT(c < MaxCharType);
223         unsigned short val = static_cast<unsigned short>(c);
224         if (metrics_cache_[val].ascent == BadMetrics)
225                 fillCache(val);
226
227         return metrics_cache_[val].ascent;
228 }
229
230
231 int GuiFontMetrics::descent(char_type c) const
232 {
233         // FIXME: The following cast is not a real conversion but it work
234         // for the ucs2 subrange of unicode. Instead of an assertion we should
235         // give the metrics of some special characters that indicates that
236         // its display is not supported.
237         BOOST_ASSERT(c < MaxCharType);
238         unsigned short val = static_cast<unsigned short>(c);
239         if (metrics_cache_[val].descent == BadMetrics)
240                 fillCache(val);
241
242         return metrics_cache_[val].descent;
243 }
244
245 #endif
246
247 } // frontend
248 } // lyx