]> git.lyx.org Git - lyx.git/blob - src/frontends/qt4/GuiFontMetrics.cpp
This commit allows to support the full unicode range in GuiFontMetrics thus fixing...
[lyx.git] / src / frontends / qt4 / GuiFontMetrics.cpp
1 /**
2  * \file GuiFontMetrics.cpp
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 #include "Dimension.h"
20
21 #include "support/unicode.h"
22
23 using std::string;
24
25 namespace lyx {
26 namespace frontend {
27
28 GuiFontMetrics::GuiFontMetrics(QFont const & font)
29 : metrics_(font), smallcaps_metrics_(font), smallcaps_shape_(false)
30 {
31 }
32
33
34 GuiFontMetrics::GuiFontMetrics(QFont const & font, QFont const & smallcaps_font)
35 : metrics_(font), smallcaps_metrics_(smallcaps_font), smallcaps_shape_(true)
36 {
37 }
38
39
40 int GuiFontMetrics::maxAscent() const
41 {
42         return metrics_.ascent();
43 }
44
45
46 int GuiFontMetrics::maxDescent() const
47 {
48         // We add 1 as the value returned by QT is different than X
49         // See http://doc.trolltech.com/2.3/qfontmetrics.html#200b74
50         return metrics_.descent() + 1;
51 }
52
53
54 int GuiFontMetrics::lbearing(char_type c) const
55 {
56         if (!is_utf16(c))
57                 // FIXME: QFontMetrics::leftBearingdoes not support the
58                 //        full unicode range. Once it does, we could use:
59                 //return metrics_.leftBearing(toqstr(docstring(1,c)));
60                 return 0;
61
62         return metrics_.leftBearing(ucs4_to_qchar(c));
63 }
64
65
66 int GuiFontMetrics::rbearing(char_type c) const
67 {
68         if (!rbearing_cache_.contains(c)) {
69                 // Qt rbearing is from the right edge of the char's width().
70                 int rb;
71                 if (is_utf16(c)) {
72                         QChar sc = ucs4_to_qchar(c);
73                         rb = width(c) - metrics_.rightBearing(sc);
74                 } else
75                         // FIXME: QFontMetrics::leftBearingdoes not support the
76                         //        full unicode range. Once it does, we could use:
77                         // metrics_.rightBearing(toqstr(docstring(1,c)));
78                         rb = width(c);
79
80                 rbearing_cache_.insert(c, rb);
81         }
82         return rbearing_cache_.value(c);
83 }
84
85
86 int GuiFontMetrics::smallcapsWidth(char_type c) const
87 {
88         // FIXME: Optimisation probably needed: we don't use the width cache.
89         if (is_utf16(c)) {
90                 QChar const qc = ucs4_to_qchar(c);
91                 QChar const uc = qc.toUpper();
92                 if (qc != uc)
93                         return smallcaps_metrics_.width(uc);
94                 else
95                         return metrics_.width(qc);
96         } else {
97                 QString const s = toqstr(docstring(1,c));
98                 QString const us = s.toUpper();
99                 if (s != us)
100                         return smallcaps_metrics_.width(us);
101                 else
102                         return metrics_.width(s);
103         }
104 }
105
106
107 int GuiFontMetrics::width(docstring const & s) const
108 {
109         size_t ls = s.size();
110         int w = 0;
111         for (unsigned int i = 0; i < ls; ++i)
112                 w += width(s[i]);
113
114         return w;
115 }
116
117
118 int GuiFontMetrics::width(QString const & ucs2) const
119 {
120         return width(qstring_to_ucs4(ucs2));
121 }
122
123
124 int GuiFontMetrics::signedWidth(docstring const & s) const
125 {
126         if (s.empty())
127                 return 0;
128
129         if (s[0] == '-')
130                 return -width(s.substr(1, s.size() - 1));
131         else
132                 return width(s);
133 }
134
135
136 void GuiFontMetrics::rectText(docstring const & str,
137         int & w, int & ascent, int & descent) const
138 {
139         static int const d = 2;
140         w = width(str) + d * 2 + 2;
141         ascent = metrics_.ascent() + d;
142         descent = metrics_.descent() + d;
143 }
144
145
146
147 void GuiFontMetrics::buttonText(docstring const & str,
148         int & w, int & ascent, int & descent) const
149 {
150         static int const d = 3;
151         w = width(str) + d * 2 + 2;
152         ascent = metrics_.ascent() + d;
153         descent = metrics_.descent() + d;
154 }
155
156
157 Dimension const GuiFontMetrics::defaultDimension() const
158 {
159         return Dimension(0, maxAscent(), maxDescent());
160 }
161
162
163 Dimension const GuiFontMetrics::dimension(char_type c) const
164 {
165         return Dimension(width(c), ascent(c), descent(c));
166 }
167
168
169 void GuiFontMetrics::fillMetricsCache(char_type c) const
170 {
171         QRect r;
172         if (is_utf16(c))
173                 r = metrics_.boundingRect(ucs4_to_qchar(c));
174         else
175                 r = metrics_.boundingRect(toqstr(docstring(1,c)));
176
177         AscendDescend ad = { -r.top(), r.bottom() + 1};
178         // We could as well compute the width but this is not really
179         // needed for now as it is done directly in width() below.
180         metrics_cache_.insert(c, ad);
181 }
182
183
184 int GuiFontMetrics::width(char_type c) const
185 {
186         if (smallcaps_shape_)
187                 return smallcapsWidth(c);
188
189         if (!width_cache_.contains(c)) {
190                 if (is_utf16(c))
191                         width_cache_.insert(c, metrics_.width(ucs4_to_qchar(c)));
192                 else
193                         width_cache_.insert(c, metrics_.width(toqstr(docstring(1,c))));
194         }
195
196         return width_cache_.value(c);
197 }
198
199
200 int GuiFontMetrics::ascent(char_type c) const
201 {
202         if (!metrics_cache_.contains(c))
203                 fillMetricsCache(c);
204
205         return metrics_cache_.value(c).ascent;
206 }
207
208
209 int GuiFontMetrics::descent(char_type c) const
210 {
211         if (!metrics_cache_.contains(c))
212                 fillMetricsCache(c);
213
214         return metrics_cache_.value(c).descent;
215 }
216
217 } // frontend
218 } // lyx