]> git.saurik.com Git - wxWidgets.git/blob - src/common/textmeasurecmn.cpp
Fix for #15520: wxRichTextCtrl: Drawing the selection doesn't respect its container...
[wxWidgets.git] / src / common / textmeasurecmn.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/textmeasurecmn.cpp
3 // Purpose: wxTextMeasureBase implementation
4 // Author: Manuel Martin
5 // Created: 2012-10-05
6 // Copyright: (c) 1997-2012 wxWidgets team
7 // Licence: wxWindows licence
8 ///////////////////////////////////////////////////////////////////////////////
9
10 // ============================================================================
11 // declarations
12 // ============================================================================
13
14 // ----------------------------------------------------------------------------
15 // headers
16 // ----------------------------------------------------------------------------
17
18 // for compilers that support precompilation, includes "wx.h".
19 #include "wx/wxprec.h"
20
21 #ifndef WX_PRECOMP
22 #include "wx/dc.h"
23 #include "wx/window.h"
24 #endif //WX_PRECOMP
25
26 #include "wx/private/textmeasure.h"
27
28 // ============================================================================
29 // wxTextMeasureBase implementation
30 // ============================================================================
31
32 wxTextMeasureBase::wxTextMeasureBase(const wxDC *dc, const wxFont *theFont)
33 : m_dc(dc),
34 m_win(NULL),
35 m_font(theFont)
36 {
37 wxASSERT_MSG( dc, wxS("wxTextMeasure needs a valid wxDC") );
38
39 // By default, use wxDC version, we'll explicitly reset this to false in
40 // the derived classes if the DC is of native variety.
41 m_useDCImpl = true;
42 }
43
44 wxTextMeasureBase::wxTextMeasureBase(const wxWindow *win, const wxFont *theFont)
45 : m_dc(NULL),
46 m_win(win),
47 m_font(theFont)
48 {
49 wxASSERT_MSG( win, wxS("wxTextMeasure needs a valid wxWindow") );
50
51 // We don't have any wxDC so we can't forward to it.
52 m_useDCImpl = false;
53 }
54
55 wxFont wxTextMeasureBase::GetFont() const
56 {
57 return m_font ? *m_font
58 : m_win ? m_win->GetFont()
59 : m_dc->GetFont();
60 }
61
62 void wxTextMeasureBase::CallGetTextExtent(const wxString& string,
63 wxCoord *width,
64 wxCoord *height,
65 wxCoord *descent,
66 wxCoord *externalLeading)
67 {
68 if ( m_useDCImpl )
69 m_dc->GetTextExtent(string, width, height, descent, externalLeading);
70 else
71 DoGetTextExtent(string, width, height, descent, externalLeading);
72 }
73
74 void wxTextMeasureBase::GetTextExtent(const wxString& string,
75 wxCoord *width,
76 wxCoord *height,
77 wxCoord *descent,
78 wxCoord *externalLeading)
79 {
80 // To make the code simpler, make sure that the width and height pointers
81 // are always valid, even if they point to dummy variables.
82 int unusedWidth, unusedHeight;
83 if ( !width )
84 width = &unusedWidth;
85 if ( !height )
86 height = &unusedHeight;
87
88 // Avoid even setting up the DC for measuring if we don't actually need to
89 // measure anything.
90 if ( string.empty() && !descent && !externalLeading )
91 {
92 *width =
93 *height = 0;
94
95 return;
96 }
97
98 MeasuringGuard guard(*this);
99
100 CallGetTextExtent(string, width, height, descent, externalLeading);
101 }
102
103 void wxTextMeasureBase::GetMultiLineTextExtent(const wxString& text,
104 wxCoord *width,
105 wxCoord *height,
106 wxCoord *heightOneLine)
107 {
108 MeasuringGuard guard(*this);
109
110 wxCoord widthTextMax = 0, widthLine,
111 heightTextTotal = 0, heightLineDefault = 0, heightLine = 0;
112
113 wxString curLine;
114 for ( wxString::const_iterator pc = text.begin(); ; ++pc )
115 {
116 if ( pc == text.end() || *pc == wxS('\n') )
117 {
118 if ( curLine.empty() )
119 {
120 // we can't use GetTextExtent - it will return 0 for both width
121 // and height and an empty line should count in height
122 // calculation
123
124 // assume that this line has the same height as the previous
125 // one
126 if ( !heightLineDefault )
127 heightLineDefault = heightLine;
128
129 if ( !heightLineDefault )
130 {
131 // but we don't know it yet - choose something reasonable
132 int dummy;
133 CallGetTextExtent(wxS("W"), &dummy, &heightLineDefault);
134 }
135
136 heightTextTotal += heightLineDefault;
137 }
138 else
139 {
140 CallGetTextExtent(curLine, &widthLine, &heightLine);
141 if ( widthLine > widthTextMax )
142 widthTextMax = widthLine;
143 heightTextTotal += heightLine;
144 }
145
146 if ( pc == text.end() )
147 {
148 break;
149 }
150 else // '\n'
151 {
152 curLine.clear();
153 }
154 }
155 else
156 {
157 curLine += *pc;
158 }
159 }
160
161 if ( width )
162 *width = widthTextMax;
163 if ( height )
164 *height = heightTextTotal;
165 if ( heightOneLine )
166 *heightOneLine = heightLine;
167 }
168
169 wxSize wxTextMeasureBase::GetLargestStringExtent(size_t n,
170 const wxString* strings)
171 {
172 MeasuringGuard guard(*this);
173
174 wxCoord w, h, widthMax = 0, heightMax = 0;
175 for ( size_t i = 0; i < n; ++i )
176 {
177 CallGetTextExtent(strings[i], &w, &h);
178
179 if ( w > widthMax )
180 widthMax = w;
181 if ( h > heightMax )
182 heightMax = h;
183 }
184
185 return wxSize(widthMax, heightMax);
186 }
187
188 bool wxTextMeasureBase::GetPartialTextExtents(const wxString& text,
189 wxArrayInt& widths,
190 double scaleX)
191 {
192 widths.Empty();
193 if ( text.empty() )
194 return true;
195
196 MeasuringGuard guard(*this);
197
198 widths.Add(0, text.length());
199
200 return DoGetPartialTextExtents(text, widths, scaleX);
201 }
202
203 // ----------------------------------------------------------------------------
204 // Generic and inefficient DoGetPartialTextExtents() implementation.
205 // ----------------------------------------------------------------------------
206
207 // Each element of the widths array will be the width of the string up to and
208 // including the corresponding character in text. This is the generic
209 // implementation, the port-specific classes should do this with native APIs
210 // if available and if faster. Note: pango_layout_index_to_pos is much slower
211 // than calling GetTextExtent!!
212
213 #define FWC_SIZE 256
214
215 class FontWidthCache
216 {
217 public:
218 FontWidthCache() : m_scaleX(1), m_widths(NULL) { }
219 ~FontWidthCache() { delete []m_widths; }
220
221 void Reset()
222 {
223 if ( !m_widths )
224 m_widths = new int[FWC_SIZE];
225
226 memset(m_widths, 0, sizeof(int)*FWC_SIZE);
227 }
228
229 wxFont m_font;
230 double m_scaleX;
231 int *m_widths;
232 };
233
234 static FontWidthCache s_fontWidthCache;
235
236 bool wxTextMeasureBase::DoGetPartialTextExtents(const wxString& text,
237 wxArrayInt& widths,
238 double scaleX)
239 {
240 int totalWidth = 0;
241
242 // reset the cache if font or horizontal scale have changed
243 if ( !s_fontWidthCache.m_widths ||
244 !wxIsSameDouble(s_fontWidthCache.m_scaleX, scaleX) ||
245 (s_fontWidthCache.m_font != *m_font) )
246 {
247 s_fontWidthCache.Reset();
248 s_fontWidthCache.m_font = *m_font;
249 s_fontWidthCache.m_scaleX = scaleX;
250 }
251
252 // Calculate the position of each character based on the widths of
253 // the previous characters. This is inexact for not fixed fonts.
254 int n = 0;
255 for ( wxString::const_iterator it = text.begin();
256 it != text.end();
257 ++it )
258 {
259 const wxChar c = *it;
260 unsigned int c_int = (unsigned int)c;
261
262 int w;
263 if ((c_int < FWC_SIZE) && (s_fontWidthCache.m_widths[c_int] != 0))
264 {
265 w = s_fontWidthCache.m_widths[c_int];
266 }
267 else
268 {
269 DoGetTextExtent(c, &w, NULL);
270 if (c_int < FWC_SIZE)
271 s_fontWidthCache.m_widths[c_int] = w;
272 }
273
274 totalWidth += w;
275 widths[n++] = totalWidth;
276 }
277
278 return true;
279 }
280